From 013818c4af0fc8f079d1a88020d2fc50767355b9 Mon Sep 17 00:00:00 2001 From: Sebastian Ramacher Date: Tue, 22 Dec 2020 18:32:50 +0100 Subject: [PATCH] New upstream version 26.1.0+dfsg1 --- .github/workflows/main.yml | 160 ++-- AUTHORS | 261 ++++-- CI/before-script-linux.sh | 2 +- CI/before-script-osx.sh | 1 - CI/full-build-macos.sh | 72 +- CI/install-dependencies-linux.sh | 4 +- CI/install-script-win.cmd | 9 +- .../macos/package/settings.json.template | 2 +- CI/scripts/macos/packageApp.sh | 78 -- CI/scripts/macos/prepareApp.sh | 41 - CMakeLists.txt | 2 +- CONTRIBUTING.rst | 6 +- UI/CMakeLists.txt | 10 +- UI/adv-audio-control.cpp | 34 +- UI/context-bar-controls.cpp | 12 +- UI/data/locale.ini | 6 + UI/data/locale/af-ZA.ini | 1 + UI/data/locale/ar-SA.ini | 32 +- UI/data/locale/az-AZ.ini | 162 +++- UI/data/locale/ba-RU.ini | 5 + UI/data/locale/bg-BG.ini | 7 +- UI/data/locale/bn-BD.ini | 4 +- UI/data/locale/ca-ES.ini | 38 +- UI/data/locale/cs-CZ.ini | 38 +- UI/data/locale/da-DK.ini | 36 +- UI/data/locale/de-DE.ini | 234 ++--- UI/data/locale/el-GR.ini | 39 +- UI/data/locale/en-GB.ini | 656 ++++++++++++- UI/data/locale/en-US.ini | 37 +- UI/data/locale/eo-UY.ini | 324 +++++++ UI/data/locale/es-ES.ini | 38 +- UI/data/locale/et-EE.ini | 8 + UI/data/locale/eu-ES.ini | 40 +- UI/data/locale/fa-IR.ini | 339 ++++++- UI/data/locale/fi-FI.ini | 37 +- UI/data/locale/fil-PH.ini | 75 +- UI/data/locale/fr-FR.ini | 36 +- UI/data/locale/gd-GB.ini | 7 +- UI/data/locale/gl-ES.ini | 40 +- UI/data/locale/he-IL.ini | 38 +- UI/data/locale/hi-IN.ini | 1 + UI/data/locale/hr-HR.ini | 6 +- UI/data/locale/hu-HU.ini | 39 +- UI/data/locale/id-ID.ini | 179 ++-- UI/data/locale/ig-NG.ini | 1 + UI/data/locale/it-IT.ini | 36 +- UI/data/locale/ja-JP.ini | 27 +- UI/data/locale/ka-GE.ini | 43 +- UI/data/locale/kab-KAB.ini | 804 ++++++++++++++++ UI/data/locale/ko-KR.ini | 60 +- UI/data/locale/ku-TR.ini | 1 + UI/data/locale/lt-LT.ini | 34 + UI/data/locale/mn-MN.ini | 3 +- UI/data/locale/ms-MY.ini | 2 +- UI/data/locale/nb-NO.ini | 46 +- UI/data/locale/nl-NL.ini | 468 +++++----- UI/data/locale/nn-NO.ini | 1 + UI/data/locale/pa-IN.ini | 1 + UI/data/locale/pl-PL.ini | 38 +- UI/data/locale/pt-BR.ini | 682 +++++++------- UI/data/locale/pt-PT.ini | 58 +- UI/data/locale/ro-RO.ini | 91 +- UI/data/locale/ru-RU.ini | 37 +- UI/data/locale/si-LK.ini | 1 + UI/data/locale/sk-SK.ini | 42 +- UI/data/locale/sl-SI.ini | 91 +- UI/data/locale/sq-AL.ini | 1 + UI/data/locale/sr-CS.ini | 7 +- UI/data/locale/sr-SP.ini | 7 +- UI/data/locale/sv-SE.ini | 59 +- UI/data/locale/ta-IN.ini | 4 +- UI/data/locale/th-TH.ini | 5 + UI/data/locale/tl-PH.ini | 7 +- UI/data/locale/tr-TR.ini | 36 +- UI/data/locale/uk-UA.ini | 50 +- UI/data/locale/ur-PK.ini | 32 + UI/data/locale/vi-VN.ini | 111 ++- UI/data/locale/zh-CN.ini | 36 +- UI/data/locale/zh-TW.ini | 38 +- UI/forms/AutoConfigStreamPage.ui | 27 +- UI/forms/NameDialog.ui | 105 --- UI/forms/OBSBasicFilters.ui | 24 + UI/forms/OBSBasicSettings.ui | 455 ++++----- UI/forms/images/obs_256x256.png | Bin 0 -> 163961 bytes UI/forms/images/obs_macos.png | Bin 0 -> 11224 bytes UI/forms/images/obs_paused_macos.png | Bin 0 -> 10798 bytes UI/forms/images/tray_active_macos.png | Bin 0 -> 11588 bytes UI/forms/obs.qrc | 4 + UI/frontend-plugins/CMakeLists.txt | 1 + .../decklink-captions/CMakeLists.txt | 44 + .../decklink-captions/data/.keepme | 0 .../decklink-captions/decklink-captions.cpp | 159 ++++ .../decklink-captions/decklink-captions.h | 30 + .../decklink-captions/forms/captions.ui | 115 +++ .../frontend-tools/CMakeLists.txt | 28 +- .../frontend-tools/data/locale/az-AZ.ini | 42 + .../frontend-tools/data/locale/de-DE.ini | 10 +- .../frontend-tools/data/locale/el-GR.ini | 3 + .../frontend-tools/data/locale/eo-UY.ini | 48 + .../frontend-tools/data/locale/es-ES.ini | 6 +- .../frontend-tools/data/locale/et-EE.ini | 6 + .../frontend-tools/data/locale/eu-ES.ini | 5 + .../frontend-tools/data/locale/fa-IR.ini | 23 + .../frontend-tools/data/locale/kab-KAB.ini | 48 + .../frontend-tools/data/locale/nb-NO.ini | 5 + .../frontend-tools/data/locale/pl-PL.ini | 2 +- .../frontend-tools/data/locale/pt-BR.ini | 30 +- .../frontend-tools/data/locale/pt-PT.ini | 3 + .../frontend-tools/data/locale/ro-RO.ini | 6 +- .../frontend-tools/data/locale/sl-SI.ini | 2 + .../frontend-tools/data/locale/sv-SE.ini | 6 +- .../frontend-tools/data/locale/vi-VN.ini | 6 + .../frontend-tools/frontend-tools-config.h.in | 1 - .../frontend-tools/frontend-tools.c | 6 +- UI/hotkey-edit.cpp | 4 +- UI/installer/mp-installer.nsi | 41 +- UI/obs-app.cpp | 43 +- UI/obs-frontend-api/obs-frontend-api.h | 1 + UI/platform-osx.mm | 23 + UI/platform-x11.cpp | 143 +++ UI/platform.hpp | 7 + UI/properties-view.cpp | 4 +- UI/qt-wrappers.cpp | 11 + UI/qt-wrappers.hpp | 3 + UI/slider-absoluteset-style.cpp | 2 +- UI/slider-ignorewheel.cpp | 75 ++ UI/slider-ignorewheel.hpp | 34 + UI/source-tree.cpp | 12 +- UI/volume-control.cpp | 6 +- UI/win-update/updater/CMakeLists.txt | 5 +- UI/win-update/updater/updater.cpp | 214 +++-- UI/win-update/updater/updater.hpp | 2 +- UI/win-update/win-update-helpers.hpp | 69 -- UI/win-update/win-update.cpp | 31 +- UI/window-basic-auto-config-test.cpp | 42 + UI/window-basic-auto-config.cpp | 37 +- UI/window-basic-auto-config.hpp | 1 + UI/window-basic-filters.cpp | 119 ++- UI/window-basic-filters.hpp | 8 +- UI/window-basic-interaction.cpp | 16 +- UI/window-basic-main-outputs.cpp | 203 +++- UI/window-basic-main-outputs.hpp | 1 + UI/window-basic-main-profiles.cpp | 38 +- UI/window-basic-main-transitions.cpp | 50 +- UI/window-basic-main.cpp | 173 +++- UI/window-basic-main.hpp | 6 +- UI/window-basic-settings-stream.cpp | 501 +++++++++- UI/window-basic-settings.cpp | 189 +++- UI/window-basic-settings.hpp | 25 +- UI/window-basic-stats.cpp | 39 +- UI/window-basic-status-bar.cpp | 3 +- UI/window-importer.cpp | 17 +- UI/window-namedialog.cpp | 91 +- UI/window-namedialog.hpp | 27 +- UI/window-projector.cpp | 6 +- cmake/Modules/CopyMSVCBins.cmake | 6 + cmake/Modules/FindSndio.cmake | 71 ++ deps/CMakeLists.txt | 4 +- deps/json11/json11.cpp | 8 +- deps/media-playback/media-playback/decode.c | 6 +- deps/obs-scripting/CMakeLists.txt | 4 - deps/obs-scripting/obs-scripting-config.h.in | 1 - deps/obs-scripting/obs-scripting-lua.c | 2 +- docs/sphinx/reference-frontend-api.rst | 6 +- docs/sphinx/reference-scenes.rst | 4 +- libobs-d3d11/d3d11-subsystem.cpp | 17 + libobs-d3d11/d3d11-subsystem.hpp | 1 + libobs-d3d11/d3d11-texture2d.cpp | 27 + libobs-opengl/CMakeLists.txt | 4 - libobs-winrt/winrt-capture.cpp | 2 +- libobs-winrt/winrt-capture.h | 2 +- libobs/CMakeLists.txt | 21 +- .../pulse/pulseaudio-output.c | 14 + libobs/graphics/graphics-imports.c | 1 + libobs/graphics/graphics-internal.h | 2 + libobs/graphics/graphics.c | 12 + libobs/graphics/graphics.h | 2 + libobs/media-io/media-remux.c | 6 + libobs/obs-audio.c | 2 +- libobs/obs-config.h | 4 +- libobs/obs-data.c | 4 +- libobs/obs-internal.h | 12 + libobs/obs-nix.c | 31 +- libobs/obs-output.c | 96 +- libobs/obs-service.c | 48 + libobs/obs-service.h | 13 +- libobs/obs-source.c | 78 ++ libobs/obs-source.h | 5 + libobs/obs.h | 34 +- libobs/obsconfig.h.in | 1 - libobs/util/bitstream.c | 52 ++ libobs/util/bitstream.h | 29 + libobs/util/pipe-windows.c | 8 +- libobs/util/platform-nix.c | 62 +- libobs/util/profiler.c | 4 + plugins/CMakeLists.txt | 6 + .../coreaudio-encoder/data/locale/az-AZ.ini | 6 + .../coreaudio-encoder/data/locale/de-DE.ini | 8 +- .../coreaudio-encoder/data/locale/eo-UY.ini | 6 + .../coreaudio-encoder/data/locale/fa-IR.ini | 1 + .../coreaudio-encoder/data/locale/ka-GE.ini | 2 +- .../coreaudio-encoder/data/locale/kab-KAB.ini | 6 + .../coreaudio-encoder/data/locale/ro-RO.ini | 2 +- plugins/decklink/OBSVideoFrame.cpp | 83 ++ plugins/decklink/OBSVideoFrame.h | 76 ++ plugins/decklink/data/locale/az-AZ.ini | 24 + plugins/decklink/data/locale/de-DE.ini | 16 +- plugins/decklink/data/locale/el-GR.ini | 4 + plugins/decklink/data/locale/eo-UY.ini | 26 + plugins/decklink/data/locale/et-EE.ini | 20 + plugins/decklink/data/locale/eu-ES.ini | 1 - plugins/decklink/data/locale/fa-IR.ini | 4 + plugins/decklink/data/locale/he-IL.ini | 9 + plugins/decklink/data/locale/kab-KAB.ini | 26 + plugins/decklink/data/locale/ro-RO.ini | 4 +- plugins/decklink/data/locale/ru-RU.ini | 2 +- plugins/decklink/decklink-device-instance.cpp | 194 +++- plugins/decklink/decklink-device-instance.hpp | 5 + plugins/decklink/decklink-device.cpp | 7 +- plugins/decklink/decklink-source.cpp | 6 +- plugins/decklink/linux/CMakeLists.txt | 8 +- .../decklink/linux/decklink-sdk/DeckLinkAPI.h | 558 ++++++----- .../decklink-sdk/DeckLinkAPIConfiguration.h | 54 +- .../DeckLinkAPIConfiguration_v10_11.h | 71 ++ .../decklink-sdk/DeckLinkAPIDeckControl.h | 74 +- .../linux/decklink-sdk/DeckLinkAPIDiscovery.h | 18 +- .../decklink-sdk/DeckLinkAPIDispatch.cpp | 4 +- .../DeckLinkAPIDispatch_v10_11.cpp | 160 ++++ .../linux/decklink-sdk/DeckLinkAPIModes.h | 88 +- .../linux/decklink-sdk/DeckLinkAPITypes.h | 23 +- .../linux/decklink-sdk/DeckLinkAPIVersion.h | 4 +- .../DeckLinkAPIVideoEncoderInput_v10_11.h | 74 ++ .../DeckLinkAPIVideoInput_v10_11.h | 76 ++ .../DeckLinkAPIVideoInput_v11_4.h | 75 ++ .../DeckLinkAPIVideoInput_v11_5_1.h | 89 ++ .../DeckLinkAPIVideoOutput_v10_11.h | 94 ++ .../DeckLinkAPIVideoOutput_v11_4.h | 87 ++ .../linux/decklink-sdk/DeckLinkAPI_v10_11.h | 121 +++ .../linux/decklink-sdk/DeckLinkAPI_v11_5.h | 100 ++ .../linux/decklink-sdk/DeckLinkAPI_v11_5_1.h | 44 + .../linux/decklink-sdk/DeckLinkAPI_v7_1.h | 5 +- .../linux/decklink-sdk/DeckLinkAPI_v7_3.h | 5 +- .../linux/decklink-sdk/DeckLinkAPI_v7_6.h | 5 +- .../linux/decklink-sdk/DeckLinkAPI_v9_2.h | 3 +- .../linux/decklink-sdk/DeckLinkAPI_v9_9.h | 3 +- plugins/decklink/mac/CMakeLists.txt | 10 +- .../decklink/mac/decklink-sdk/DeckLinkAPI.h | 866 ++++++++++-------- .../decklink-sdk/DeckLinkAPIConfiguration.h | 204 +++-- .../DeckLinkAPIConfiguration_v10_11.h | 71 ++ .../mac/decklink-sdk/DeckLinkAPIDeckControl.h | 136 +-- .../mac/decklink-sdk/DeckLinkAPIDiscovery.h | 18 +- .../mac/decklink-sdk/DeckLinkAPIDispatch.cpp | 4 +- .../DeckLinkAPIDispatch_v10_11.cpp | 206 +++++ .../mac/decklink-sdk/DeckLinkAPIModes.h | 240 +++-- .../mac/decklink-sdk/DeckLinkAPIStreaming.h | 138 +-- .../DeckLinkAPIStreaming_v10_11.h | 46 + .../mac/decklink-sdk/DeckLinkAPITypes.h | 23 +- .../mac/decklink-sdk/DeckLinkAPIVersion.h | 4 +- .../DeckLinkAPIVideoEncoderInput_v10_11.h | 75 ++ .../DeckLinkAPIVideoInput_v10_11.h | 77 ++ .../DeckLinkAPIVideoInput_v11_4.h | 76 ++ .../DeckLinkAPIVideoInput_v11_5_1.h | 89 ++ .../DeckLinkAPIVideoOutput_v10_11.h | 95 ++ .../DeckLinkAPIVideoOutput_v11_4.h | 88 ++ .../mac/decklink-sdk/DeckLinkAPI_v10_11.h | 122 +++ .../mac/decklink-sdk/DeckLinkAPI_v11_5.h | 100 ++ .../mac/decklink-sdk/DeckLinkAPI_v11_5_1.h | 44 + .../mac/decklink-sdk/DeckLinkAPI_v7_1.h | 5 +- .../mac/decklink-sdk/DeckLinkAPI_v7_3.h | 4 +- .../mac/decklink-sdk/DeckLinkAPI_v7_6.h | 5 +- .../mac/decklink-sdk/DeckLinkAPI_v9_2.h | 3 +- .../mac/decklink-sdk/DeckLinkAPI_v9_9.h | 3 +- plugins/decklink/platform.hpp | 1 + plugins/decklink/win/CMakeLists.txt | 13 +- .../decklink/win/decklink-sdk/DeckLinkAPI.idl | 762 ++++++++------- .../decklink-sdk/DeckLinkAPIConfiguration.idl | 71 +- .../decklink-sdk/DeckLinkAPIDeckControl.idl | 99 +- .../win/decklink-sdk/DeckLinkAPIDiscovery.idl | 15 +- .../win/decklink-sdk/DeckLinkAPIModes.idl | 103 ++- .../win/decklink-sdk/DeckLinkAPIStreaming.idl | 143 ++- .../win/decklink-sdk/DeckLinkAPITypes.idl | 30 +- .../win/decklink-sdk/DeckLinkAPIVersion.h | 4 +- .../win/decklink-sdk/DeckLinkAPI_v10_11.idl | 289 ++++++ .../win/decklink-sdk/DeckLinkAPI_v11_4.idl | 120 +++ .../win/decklink-sdk/DeckLinkAPI_v11_5.idl | 99 ++ .../win/decklink-sdk/DeckLinkAPI_v11_5_1.idl | 90 ++ .../win/decklink-sdk/DeckLinkAPI_v7_1.idl | 4 +- .../win/decklink-sdk/DeckLinkAPI_v7_3.idl | 4 +- .../win/decklink-sdk/DeckLinkAPI_v7_6.idl | 4 +- .../win/decklink-sdk/DeckLinkAPI_v9_2.idl | 2 +- .../win/decklink-sdk/DeckLinkAPI_v9_9.idl | 2 +- plugins/decklink/win/platform.cpp | 10 + plugins/image-source/data/locale/az-AZ.ini | 36 + plugins/image-source/data/locale/et-EE.ini | 7 + plugins/image-source/data/locale/fa-IR.ini | 3 + plugins/image-source/data/locale/he-IL.ini | 4 + plugins/image-source/data/locale/kab-KAB.ini | 36 + plugins/image-source/data/locale/pt-BR.ini | 22 +- plugins/image-source/data/locale/pt-PT.ini | 7 + plugins/image-source/data/locale/ro-RO.ini | 10 +- plugins/linux-alsa/alsa-input.c | 24 +- plugins/linux-alsa/data/locale/az-AZ.ini | 3 + plugins/linux-alsa/data/locale/kab-KAB.ini | 3 + plugins/linux-alsa/data/locale/pt-BR.ini | 2 +- plugins/linux-capture/data/locale/az-AZ.ini | 14 + plugins/linux-capture/data/locale/de-DE.ini | 8 +- plugins/linux-capture/data/locale/kab-KAB.ini | 16 + plugins/linux-capture/data/locale/pt-BR.ini | 4 +- plugins/linux-jack/data/locale/az-AZ.ini | 4 + plugins/linux-jack/data/locale/de-DE.ini | 4 +- plugins/linux-jack/data/locale/kab-KAB.ini | 4 + .../linux-pulseaudio/data/locale/az-AZ.ini | 4 + .../linux-pulseaudio/data/locale/kab-KAB.ini | 4 + plugins/linux-v4l2/CMakeLists.txt | 1 + plugins/linux-v4l2/data/locale/az-AZ.ini | 16 + plugins/linux-v4l2/data/locale/de-DE.ini | 2 +- plugins/linux-v4l2/data/locale/el-GR.ini | 5 + plugins/linux-v4l2/data/locale/et-EE.ini | 5 + plugins/linux-v4l2/data/locale/fa-IR.ini | 1 + plugins/linux-v4l2/data/locale/kab-KAB.ini | 16 + plugins/linux-v4l2/data/locale/pt-BR.ini | 4 +- plugins/linux-v4l2/data/locale/ro-RO.ini | 2 +- plugins/linux-v4l2/data/locale/vi-VN.ini | 8 + plugins/linux-v4l2/linux-v4l2.c | 31 +- plugins/linux-v4l2/v4l2-output.c | 176 ++++ plugins/mac-avcapture/data/locale/az-AZ.ini | 14 + plugins/mac-avcapture/data/locale/kab-KAB.ini | 14 + plugins/mac-avcapture/data/locale/pt-BR.ini | 2 +- plugins/mac-avcapture/data/locale/pt-PT.ini | 1 + plugins/mac-avcapture/data/locale/vi-VN.ini | 7 + plugins/mac-capture/CMakeLists.txt | 5 - plugins/mac-capture/data/locale/az-AZ.ini | 19 + plugins/mac-capture/data/locale/kab-KAB.ini | 21 + plugins/mac-capture/data/locale/pt-BR.ini | 8 +- plugins/mac-capture/data/locale/vi-VN.ini | 3 + plugins/mac-syphon/CMakeLists.txt | 3 - plugins/mac-syphon/data/locale/az-AZ.ini | 13 + plugins/mac-syphon/data/locale/de-DE.ini | 4 +- plugins/mac-syphon/data/locale/et-EE.ini | 1 + plugins/mac-syphon/data/locale/kab-KAB.ini | 13 + plugins/mac-syphon/data/locale/vi-VN.ini | 4 + plugins/mac-virtualcam/CMakeLists.txt | 2 + plugins/mac-virtualcam/data/locale/en-US.ini | 0 .../mac-virtualcam/src/common/MachProtocol.h | 17 + .../src/dal-plugin/CMSampleBufferUtils.h | 22 + .../src/dal-plugin/CMSampleBufferUtils.mm | 187 ++++ .../src/dal-plugin/CMakeLists.txt | 109 +++ .../mac-virtualcam/src/dal-plugin/Defines.h | 21 + .../mac-virtualcam/src/dal-plugin/Info.plist | 40 + .../mac-virtualcam/src/dal-plugin/Logging.h | 32 + .../src/dal-plugin/OBSDALDevice.h | 34 + .../src/dal-plugin/OBSDALDevice.mm | 295 ++++++ .../src/dal-plugin/OBSDALMachClient.h | 33 + .../src/dal-plugin/OBSDALMachClient.mm | 140 +++ .../src/dal-plugin/OBSDALObjectStore.h | 62 ++ .../src/dal-plugin/OBSDALObjectStore.mm | 281 ++++++ .../src/dal-plugin/OBSDALPlugInInterface.h | 23 + .../src/dal-plugin/OBSDALPlugInInterface.mm | 457 +++++++++ .../src/dal-plugin/OBSDALPlugin.h | 51 ++ .../src/dal-plugin/OBSDALPlugin.mm | 255 ++++++ .../src/dal-plugin/OBSDALPluginMain.mm | 37 + .../src/dal-plugin/OBSDALStream.h | 48 + .../src/dal-plugin/OBSDALStream.mm | 570 ++++++++++++ .../src/dal-plugin/placeholder.png | Bin 0 -> 314050 bytes .../src/obs-plugin/CMakeLists.txt | 59 ++ .../mac-virtualcam/src/obs-plugin/Defines.h | 24 + .../src/obs-plugin/OBSDALMachServer.h | 29 + .../src/obs-plugin/OBSDALMachServer.mm | 178 ++++ .../src/obs-plugin/data/locale/ar-SA.ini | 2 + .../src/obs-plugin/data/locale/az-AZ.ini | 2 + .../src/obs-plugin/data/locale/ca-ES.ini | 2 + .../src/obs-plugin/data/locale/cs-CZ.ini | 2 + .../src/obs-plugin/data/locale/da-DK.ini | 2 + .../src/obs-plugin/data/locale/de-DE.ini | 2 + .../src/obs-plugin/data/locale/en-GB.ini | 2 + .../src/obs-plugin/data/locale/en-US.ini | 1 + .../src/obs-plugin/data/locale/es-ES.ini | 2 + .../src/obs-plugin/data/locale/et-EE.ini | 2 + .../src/obs-plugin/data/locale/fa-IR.ini | 2 + .../src/obs-plugin/data/locale/fi-FI.ini | 2 + .../src/obs-plugin/data/locale/fr-FR.ini | 2 + .../src/obs-plugin/data/locale/gl-ES.ini | 2 + .../src/obs-plugin/data/locale/he-IL.ini | 2 + .../src/obs-plugin/data/locale/hu-HU.ini | 2 + .../src/obs-plugin/data/locale/id-ID.ini | 2 + .../src/obs-plugin/data/locale/it-IT.ini | 2 + .../src/obs-plugin/data/locale/ja-JP.ini | 2 + .../src/obs-plugin/data/locale/ka-GE.ini | 2 + .../src/obs-plugin/data/locale/kab-KAB.ini | 2 + .../src/obs-plugin/data/locale/ko-KR.ini | 2 + .../src/obs-plugin/data/locale/nl-NL.ini | 2 + .../src/obs-plugin/data/locale/pl-PL.ini | 2 + .../src/obs-plugin/data/locale/pt-BR.ini | 2 + .../src/obs-plugin/data/locale/pt-PT.ini | 2 + .../src/obs-plugin/data/locale/ru-RU.ini | 2 + .../src/obs-plugin/data/locale/sk-SK.ini | 2 + .../src/obs-plugin/data/locale/sl-SI.ini | 2 + .../src/obs-plugin/data/locale/sv-SE.ini | 2 + .../src/obs-plugin/data/locale/tr-TR.ini | 2 + .../src/obs-plugin/data/locale/uk-UA.ini | 2 + .../src/obs-plugin/data/locale/zh-CN.ini | 2 + .../src/obs-plugin/data/locale/zh-TW.ini | 2 + .../src/obs-plugin/plugin-main.mm | 208 +++++ plugins/mac-vth264/data/locale/az-AZ.ini | 11 + plugins/mac-vth264/data/locale/de-DE.ini | 8 +- plugins/mac-vth264/data/locale/id-ID.ini | 2 +- plugins/mac-vth264/data/locale/kab-KAB.ini | 14 + plugins/mac-vth264/data/locale/ro-RO.ini | 2 +- plugins/mac-vth264/data/locale/vi-VN.ini | 1 + plugins/obs-ffmpeg/CMakeLists.txt | 4 +- plugins/obs-ffmpeg/data/locale/de-DE.ini | 30 +- plugins/obs-ffmpeg/data/locale/el-GR.ini | 20 + plugins/obs-ffmpeg/data/locale/fa-IR.ini | 30 + plugins/obs-ffmpeg/data/locale/fil-PH.ini | 10 + plugins/obs-ffmpeg/data/locale/id-ID.ini | 2 +- plugins/obs-ffmpeg/data/locale/kab-KAB.ini | 53 ++ plugins/obs-ffmpeg/data/locale/ko-KR.ini | 4 +- plugins/obs-ffmpeg/data/locale/nb-NO.ini | 2 + plugins/obs-ffmpeg/data/locale/pt-BR.ini | 8 +- plugins/obs-ffmpeg/data/locale/pt-PT.ini | 1 + plugins/obs-ffmpeg/data/locale/ro-RO.ini | 22 +- plugins/obs-ffmpeg/data/locale/sl-SI.ini | 1 + plugins/obs-ffmpeg/data/locale/sv-SE.ini | 2 +- plugins/obs-ffmpeg/data/locale/vi-VN.ini | 3 + plugins/obs-ffmpeg/ffmpeg-mux/CMakeLists.txt | 5 + plugins/obs-ffmpeg/ffmpeg-mux/ffmpeg-mux.c | 114 ++- plugins/obs-ffmpeg/ffmpeg-mux/ffmpeg-mux.h | 1 + plugins/obs-ffmpeg/jim-nvenc.c | 8 + plugins/obs-ffmpeg/obs-ffmpeg-hls-mux.c | 332 +++++++ plugins/obs-ffmpeg/obs-ffmpeg-mux.c | 117 +-- plugins/obs-ffmpeg/obs-ffmpeg-mux.h | 63 ++ plugins/obs-ffmpeg/obs-ffmpeg-nvenc.c | 4 + plugins/obs-ffmpeg/obs-ffmpeg.c | 3 + plugins/obs-filters/CMakeLists.txt | 3 + plugins/obs-filters/data/locale/de-DE.ini | 24 +- plugins/obs-filters/data/locale/el-GR.ini | 29 + plugins/obs-filters/data/locale/fa-IR.ini | 3 + plugins/obs-filters/data/locale/fil-PH.ini | 9 + plugins/obs-filters/data/locale/he-IL.ini | 3 + plugins/obs-filters/data/locale/kab-KAB.ini | 55 ++ plugins/obs-filters/data/locale/nb-NO.ini | 3 + plugins/obs-filters/data/locale/pt-BR.ini | 4 +- plugins/obs-filters/data/locale/pt-PT.ini | 1 + plugins/obs-filters/data/locale/sl-SI.ini | 3 + plugins/obs-filters/rnnoise/src/denoise.c | 40 +- plugins/obs-filters/rnnoise/src/pitch.c | 2 +- plugins/obs-filters/rnnoise/src/rnn.c | 2 +- plugins/obs-libfdk/data/locale/de-DE.ini | 4 +- plugins/obs-libfdk/data/locale/fa-IR.ini | 2 +- plugins/obs-libfdk/data/locale/kab-KAB.ini | 4 + plugins/obs-libfdk/data/locale/ur-PK.ini | 1 - plugins/obs-outputs/data/locale/ar-SA.ini | 6 + plugins/obs-outputs/data/locale/de-DE.ini | 20 +- plugins/obs-outputs/data/locale/el-GR.ini | 3 + plugins/obs-outputs/data/locale/kab-KAB.ini | 14 + plugins/obs-outputs/data/locale/ro-RO.ini | 6 +- plugins/obs-outputs/librtmp/rtmp.c | 15 +- plugins/obs-text/data/locale/de-DE.ini | 2 +- plugins/obs-text/data/locale/el-GR.ini | 6 + plugins/obs-text/data/locale/et-EE.ini | 5 + plugins/obs-text/data/locale/fa-IR.ini | 2 + plugins/obs-text/data/locale/he-IL.ini | 8 + plugins/obs-text/data/locale/kab-KAB.ini | 34 + plugins/obs-text/data/locale/nb-NO.ini | 1 + plugins/obs-text/data/locale/pt-BR.ini | 38 +- plugins/obs-text/data/locale/ro-RO.ini | 23 +- plugins/obs-transitions/data/locale/ar-SA.ini | 17 +- plugins/obs-transitions/data/locale/ba-RU.ini | 1 - plugins/obs-transitions/data/locale/bg-BG.ini | 1 - plugins/obs-transitions/data/locale/bn-BD.ini | 1 - plugins/obs-transitions/data/locale/ca-ES.ini | 2 +- plugins/obs-transitions/data/locale/cs-CZ.ini | 2 +- plugins/obs-transitions/data/locale/da-DK.ini | 2 +- plugins/obs-transitions/data/locale/de-DE.ini | 14 +- plugins/obs-transitions/data/locale/el-GR.ini | 4 +- plugins/obs-transitions/data/locale/en-GB.ini | 2 +- plugins/obs-transitions/data/locale/en-US.ini | 1 + plugins/obs-transitions/data/locale/es-ES.ini | 2 +- plugins/obs-transitions/data/locale/et-EE.ini | 1 - plugins/obs-transitions/data/locale/eu-ES.ini | 1 - plugins/obs-transitions/data/locale/fa-IR.ini | 66 ++ plugins/obs-transitions/data/locale/fi-FI.ini | 2 +- .../obs-transitions/data/locale/fil-PH.ini | 1 - plugins/obs-transitions/data/locale/fr-FR.ini | 2 +- plugins/obs-transitions/data/locale/gd-GB.ini | 1 - plugins/obs-transitions/data/locale/gl-ES.ini | 2 +- plugins/obs-transitions/data/locale/he-IL.ini | 1 - plugins/obs-transitions/data/locale/hr-HR.ini | 1 - plugins/obs-transitions/data/locale/hu-HU.ini | 2 +- plugins/obs-transitions/data/locale/id-ID.ini | 2 +- plugins/obs-transitions/data/locale/it-IT.ini | 2 +- plugins/obs-transitions/data/locale/ja-JP.ini | 2 +- plugins/obs-transitions/data/locale/ka-GE.ini | 2 +- .../obs-transitions/data/locale/kab-KAB.ini | 24 + plugins/obs-transitions/data/locale/ko-KR.ini | 2 +- plugins/obs-transitions/data/locale/nb-NO.ini | 1 - plugins/obs-transitions/data/locale/nl-NL.ini | 2 +- plugins/obs-transitions/data/locale/pl-PL.ini | 2 +- plugins/obs-transitions/data/locale/pt-BR.ini | 14 +- plugins/obs-transitions/data/locale/pt-PT.ini | 1 - plugins/obs-transitions/data/locale/ro-RO.ini | 1 - plugins/obs-transitions/data/locale/ru-RU.ini | 2 +- plugins/obs-transitions/data/locale/sk-SK.ini | 2 +- plugins/obs-transitions/data/locale/sl-SI.ini | 2 +- plugins/obs-transitions/data/locale/sr-CS.ini | 1 - plugins/obs-transitions/data/locale/sr-SP.ini | 1 - plugins/obs-transitions/data/locale/sv-SE.ini | 2 +- plugins/obs-transitions/data/locale/ta-IN.ini | 1 - plugins/obs-transitions/data/locale/tl-PH.ini | 1 - plugins/obs-transitions/data/locale/tr-TR.ini | 2 +- plugins/obs-transitions/data/locale/uk-UA.ini | 2 +- plugins/obs-transitions/data/locale/vi-VN.ini | 20 +- plugins/obs-transitions/data/locale/zh-CN.ini | 2 +- plugins/obs-transitions/data/locale/zh-TW.ini | 2 +- plugins/obs-transitions/transition-stinger.c | 12 + plugins/obs-x264/data/locale/de-DE.ini | 4 +- plugins/obs-x264/data/locale/kab-KAB.ini | 13 + plugins/obs-x264/obs-x264.c | 15 +- plugins/oss-audio/data/locale/ar-SA.ini | 9 + plugins/oss-audio/data/locale/de-DE.ini | 2 +- plugins/oss-audio/data/locale/el-GR.ini | 9 + plugins/oss-audio/data/locale/et-EE.ini | 9 + plugins/oss-audio/data/locale/fa-IR.ini | 9 + plugins/oss-audio/data/locale/fil-PH.ini | 2 + plugins/oss-audio/data/locale/ka-GE.ini | 4 +- plugins/oss-audio/data/locale/kab-KAB.ini | 9 + plugins/oss-audio/data/locale/pt-BR.ini | 2 +- plugins/oss-audio/data/locale/pt-PT.ini | 5 + plugins/oss-audio/data/locale/ro-RO.ini | 4 +- plugins/rtmp-services/data/locale/ar-SA.ini | 1 + plugins/rtmp-services/data/locale/kab-KAB.ini | 11 + plugins/rtmp-services/data/locale/sv-SE.ini | 2 +- plugins/rtmp-services/data/package.json | 4 +- plugins/rtmp-services/data/services.json | 117 ++- plugins/rtmp-services/rtmp-common.c | 117 ++- plugins/rtmp-services/rtmp-custom.c | 15 + plugins/rtmp-services/rtmp-format-ver.h | 2 +- plugins/sndio/CMakeLists.txt | 35 + plugins/sndio/data/locale/ar-SA.ini | 6 + plugins/sndio/data/locale/ca-ES.ini | 7 + plugins/sndio/data/locale/cs-CZ.ini | 7 + plugins/sndio/data/locale/da-DK.ini | 7 + plugins/sndio/data/locale/de-DE.ini | 7 + plugins/sndio/data/locale/el-GR.ini | 6 + plugins/sndio/data/locale/en-GB.ini | 7 + plugins/sndio/data/locale/en-US.ini | 6 + plugins/sndio/data/locale/es-ES.ini | 7 + plugins/sndio/data/locale/et-EE.ini | 7 + plugins/sndio/data/locale/fa-IR.ini | 7 + plugins/sndio/data/locale/fi-FI.ini | 7 + plugins/sndio/data/locale/fr-FR.ini | 7 + plugins/sndio/data/locale/gl-ES.ini | 7 + plugins/sndio/data/locale/hu-HU.ini | 4 + plugins/sndio/data/locale/id-ID.ini | 7 + plugins/sndio/data/locale/it-IT.ini | 7 + plugins/sndio/data/locale/ja-JP.ini | 7 + plugins/sndio/data/locale/ka-GE.ini | 7 + plugins/sndio/data/locale/kab-KAB.ini | 7 + plugins/sndio/data/locale/ko-KR.ini | 7 + plugins/sndio/data/locale/nl-NL.ini | 7 + plugins/sndio/data/locale/pl-PL.ini | 7 + plugins/sndio/data/locale/pt-BR.ini | 7 + plugins/sndio/data/locale/pt-PT.ini | 5 + plugins/sndio/data/locale/ru-RU.ini | 7 + plugins/sndio/data/locale/sk-SK.ini | 7 + plugins/sndio/data/locale/sl-SI.ini | 7 + plugins/sndio/data/locale/sv-SE.ini | 7 + plugins/sndio/data/locale/tr-TR.ini | 7 + plugins/sndio/data/locale/uk-UA.ini | 7 + plugins/sndio/data/locale/zh-CN.ini | 7 + plugins/sndio/data/locale/zh-TW.ini | 7 + plugins/sndio/sndio-input.c | 418 +++++++++ plugins/sndio/sndio-input.h | 18 + plugins/sndio/sndio.c | 32 + plugins/text-freetype2/CMakeLists.txt | 3 - plugins/text-freetype2/data/locale/ar-SA.ini | 2 + plugins/text-freetype2/data/locale/de-DE.ini | 2 +- plugins/text-freetype2/data/locale/el-GR.ini | 1 + plugins/text-freetype2/data/locale/fa-IR.ini | 1 + .../text-freetype2/data/locale/kab-KAB.ini | 16 + plugins/text-freetype2/data/locale/pt-BR.ini | 10 +- plugins/text-freetype2/data/locale/ro-RO.ini | 6 +- plugins/vlc-video/data/locale/de-DE.ini | 2 +- plugins/vlc-video/data/locale/el-GR.ini | 3 + plugins/vlc-video/data/locale/et-EE.ini | 7 + plugins/vlc-video/data/locale/fa-IR.ini | 4 + plugins/vlc-video/data/locale/fil-PH.ini | 1 + plugins/vlc-video/data/locale/kab-KAB.ini | 18 + plugins/vlc-video/data/locale/pt-BR.ini | 6 +- plugins/vlc-video/data/locale/ro-RO.ini | 10 +- plugins/vlc-video/vlc-video-source.c | 4 +- test/cmocka/CMakeLists.txt | 7 + test/cmocka/test_bitstream.c | 34 + test/cmocka/test_serializer.c | 1 + 594 files changed, 19576 insertions(+), 4478 deletions(-) delete mode 100755 CI/scripts/macos/packageApp.sh delete mode 100755 CI/scripts/macos/prepareApp.sh create mode 100644 UI/data/locale/eo-UY.ini create mode 100644 UI/data/locale/kab-KAB.ini delete mode 100644 UI/forms/NameDialog.ui create mode 100644 UI/forms/images/obs_256x256.png create mode 100644 UI/forms/images/obs_macos.png create mode 100644 UI/forms/images/obs_paused_macos.png create mode 100644 UI/forms/images/tray_active_macos.png create mode 100644 UI/frontend-plugins/decklink-captions/CMakeLists.txt rename config/.gitignore => UI/frontend-plugins/decklink-captions/data/.keepme (100%) create mode 100644 UI/frontend-plugins/decklink-captions/decklink-captions.cpp create mode 100644 UI/frontend-plugins/decklink-captions/decklink-captions.h create mode 100644 UI/frontend-plugins/decklink-captions/forms/captions.ui create mode 100644 UI/frontend-plugins/frontend-tools/data/locale/eo-UY.ini create mode 100644 UI/frontend-plugins/frontend-tools/data/locale/kab-KAB.ini create mode 100644 cmake/Modules/FindSndio.cmake create mode 100644 libobs/util/bitstream.c create mode 100644 libobs/util/bitstream.h create mode 100644 plugins/coreaudio-encoder/data/locale/az-AZ.ini create mode 100644 plugins/coreaudio-encoder/data/locale/eo-UY.ini create mode 100644 plugins/coreaudio-encoder/data/locale/kab-KAB.ini create mode 100644 plugins/decklink/OBSVideoFrame.cpp create mode 100644 plugins/decklink/OBSVideoFrame.h create mode 100644 plugins/decklink/data/locale/eo-UY.ini create mode 100644 plugins/decklink/data/locale/kab-KAB.ini create mode 100644 plugins/decklink/linux/decklink-sdk/DeckLinkAPIConfiguration_v10_11.h create mode 100644 plugins/decklink/linux/decklink-sdk/DeckLinkAPIDispatch_v10_11.cpp create mode 100644 plugins/decklink/linux/decklink-sdk/DeckLinkAPIVideoEncoderInput_v10_11.h create mode 100644 plugins/decklink/linux/decklink-sdk/DeckLinkAPIVideoInput_v10_11.h create mode 100644 plugins/decklink/linux/decklink-sdk/DeckLinkAPIVideoInput_v11_4.h create mode 100644 plugins/decklink/linux/decklink-sdk/DeckLinkAPIVideoInput_v11_5_1.h create mode 100644 plugins/decklink/linux/decklink-sdk/DeckLinkAPIVideoOutput_v10_11.h create mode 100644 plugins/decklink/linux/decklink-sdk/DeckLinkAPIVideoOutput_v11_4.h create mode 100644 plugins/decklink/linux/decklink-sdk/DeckLinkAPI_v10_11.h create mode 100644 plugins/decklink/linux/decklink-sdk/DeckLinkAPI_v11_5.h create mode 100644 plugins/decklink/linux/decklink-sdk/DeckLinkAPI_v11_5_1.h create mode 100644 plugins/decklink/mac/decklink-sdk/DeckLinkAPIConfiguration_v10_11.h create mode 100644 plugins/decklink/mac/decklink-sdk/DeckLinkAPIDispatch_v10_11.cpp create mode 100644 plugins/decklink/mac/decklink-sdk/DeckLinkAPIStreaming_v10_11.h create mode 100644 plugins/decklink/mac/decklink-sdk/DeckLinkAPIVideoEncoderInput_v10_11.h create mode 100644 plugins/decklink/mac/decklink-sdk/DeckLinkAPIVideoInput_v10_11.h create mode 100644 plugins/decklink/mac/decklink-sdk/DeckLinkAPIVideoInput_v11_4.h create mode 100644 plugins/decklink/mac/decklink-sdk/DeckLinkAPIVideoInput_v11_5_1.h create mode 100644 plugins/decklink/mac/decklink-sdk/DeckLinkAPIVideoOutput_v10_11.h create mode 100644 plugins/decklink/mac/decklink-sdk/DeckLinkAPIVideoOutput_v11_4.h create mode 100644 plugins/decklink/mac/decklink-sdk/DeckLinkAPI_v10_11.h create mode 100644 plugins/decklink/mac/decklink-sdk/DeckLinkAPI_v11_5.h create mode 100644 plugins/decklink/mac/decklink-sdk/DeckLinkAPI_v11_5_1.h create mode 100644 plugins/decklink/win/decklink-sdk/DeckLinkAPI_v10_11.idl create mode 100644 plugins/decklink/win/decklink-sdk/DeckLinkAPI_v11_4.idl create mode 100644 plugins/decklink/win/decklink-sdk/DeckLinkAPI_v11_5.idl create mode 100644 plugins/decklink/win/decklink-sdk/DeckLinkAPI_v11_5_1.idl create mode 100644 plugins/image-source/data/locale/az-AZ.ini create mode 100644 plugins/image-source/data/locale/kab-KAB.ini create mode 100644 plugins/linux-alsa/data/locale/az-AZ.ini create mode 100644 plugins/linux-alsa/data/locale/kab-KAB.ini create mode 100644 plugins/linux-capture/data/locale/kab-KAB.ini create mode 100644 plugins/linux-jack/data/locale/az-AZ.ini create mode 100644 plugins/linux-jack/data/locale/kab-KAB.ini create mode 100644 plugins/linux-pulseaudio/data/locale/az-AZ.ini create mode 100644 plugins/linux-pulseaudio/data/locale/kab-KAB.ini create mode 100644 plugins/linux-v4l2/data/locale/az-AZ.ini create mode 100644 plugins/linux-v4l2/data/locale/kab-KAB.ini create mode 100644 plugins/linux-v4l2/v4l2-output.c create mode 100644 plugins/mac-avcapture/data/locale/az-AZ.ini create mode 100644 plugins/mac-avcapture/data/locale/kab-KAB.ini create mode 100644 plugins/mac-capture/data/locale/kab-KAB.ini create mode 100644 plugins/mac-syphon/data/locale/az-AZ.ini create mode 100644 plugins/mac-syphon/data/locale/kab-KAB.ini create mode 100644 plugins/mac-virtualcam/CMakeLists.txt create mode 100644 plugins/mac-virtualcam/data/locale/en-US.ini create mode 100644 plugins/mac-virtualcam/src/common/MachProtocol.h create mode 100644 plugins/mac-virtualcam/src/dal-plugin/CMSampleBufferUtils.h create mode 100644 plugins/mac-virtualcam/src/dal-plugin/CMSampleBufferUtils.mm create mode 100644 plugins/mac-virtualcam/src/dal-plugin/CMakeLists.txt create mode 100755 plugins/mac-virtualcam/src/dal-plugin/Defines.h create mode 100644 plugins/mac-virtualcam/src/dal-plugin/Info.plist create mode 100644 plugins/mac-virtualcam/src/dal-plugin/Logging.h create mode 100644 plugins/mac-virtualcam/src/dal-plugin/OBSDALDevice.h create mode 100644 plugins/mac-virtualcam/src/dal-plugin/OBSDALDevice.mm create mode 100644 plugins/mac-virtualcam/src/dal-plugin/OBSDALMachClient.h create mode 100644 plugins/mac-virtualcam/src/dal-plugin/OBSDALMachClient.mm create mode 100644 plugins/mac-virtualcam/src/dal-plugin/OBSDALObjectStore.h create mode 100644 plugins/mac-virtualcam/src/dal-plugin/OBSDALObjectStore.mm create mode 100644 plugins/mac-virtualcam/src/dal-plugin/OBSDALPlugInInterface.h create mode 100644 plugins/mac-virtualcam/src/dal-plugin/OBSDALPlugInInterface.mm create mode 100644 plugins/mac-virtualcam/src/dal-plugin/OBSDALPlugin.h create mode 100644 plugins/mac-virtualcam/src/dal-plugin/OBSDALPlugin.mm create mode 100644 plugins/mac-virtualcam/src/dal-plugin/OBSDALPluginMain.mm create mode 100644 plugins/mac-virtualcam/src/dal-plugin/OBSDALStream.h create mode 100644 plugins/mac-virtualcam/src/dal-plugin/OBSDALStream.mm create mode 100644 plugins/mac-virtualcam/src/dal-plugin/placeholder.png create mode 100644 plugins/mac-virtualcam/src/obs-plugin/CMakeLists.txt create mode 100644 plugins/mac-virtualcam/src/obs-plugin/Defines.h create mode 100644 plugins/mac-virtualcam/src/obs-plugin/OBSDALMachServer.h create mode 100644 plugins/mac-virtualcam/src/obs-plugin/OBSDALMachServer.mm create mode 100644 plugins/mac-virtualcam/src/obs-plugin/data/locale/ar-SA.ini create mode 100644 plugins/mac-virtualcam/src/obs-plugin/data/locale/az-AZ.ini create mode 100644 plugins/mac-virtualcam/src/obs-plugin/data/locale/ca-ES.ini create mode 100644 plugins/mac-virtualcam/src/obs-plugin/data/locale/cs-CZ.ini create mode 100644 plugins/mac-virtualcam/src/obs-plugin/data/locale/da-DK.ini create mode 100644 plugins/mac-virtualcam/src/obs-plugin/data/locale/de-DE.ini create mode 100644 plugins/mac-virtualcam/src/obs-plugin/data/locale/en-GB.ini create mode 100644 plugins/mac-virtualcam/src/obs-plugin/data/locale/en-US.ini create mode 100644 plugins/mac-virtualcam/src/obs-plugin/data/locale/es-ES.ini create mode 100644 plugins/mac-virtualcam/src/obs-plugin/data/locale/et-EE.ini create mode 100644 plugins/mac-virtualcam/src/obs-plugin/data/locale/fa-IR.ini create mode 100644 plugins/mac-virtualcam/src/obs-plugin/data/locale/fi-FI.ini create mode 100644 plugins/mac-virtualcam/src/obs-plugin/data/locale/fr-FR.ini create mode 100644 plugins/mac-virtualcam/src/obs-plugin/data/locale/gl-ES.ini create mode 100644 plugins/mac-virtualcam/src/obs-plugin/data/locale/he-IL.ini create mode 100644 plugins/mac-virtualcam/src/obs-plugin/data/locale/hu-HU.ini create mode 100644 plugins/mac-virtualcam/src/obs-plugin/data/locale/id-ID.ini create mode 100644 plugins/mac-virtualcam/src/obs-plugin/data/locale/it-IT.ini create mode 100644 plugins/mac-virtualcam/src/obs-plugin/data/locale/ja-JP.ini create mode 100644 plugins/mac-virtualcam/src/obs-plugin/data/locale/ka-GE.ini create mode 100644 plugins/mac-virtualcam/src/obs-plugin/data/locale/kab-KAB.ini create mode 100644 plugins/mac-virtualcam/src/obs-plugin/data/locale/ko-KR.ini create mode 100644 plugins/mac-virtualcam/src/obs-plugin/data/locale/nl-NL.ini create mode 100644 plugins/mac-virtualcam/src/obs-plugin/data/locale/pl-PL.ini create mode 100644 plugins/mac-virtualcam/src/obs-plugin/data/locale/pt-BR.ini create mode 100644 plugins/mac-virtualcam/src/obs-plugin/data/locale/pt-PT.ini create mode 100644 plugins/mac-virtualcam/src/obs-plugin/data/locale/ru-RU.ini create mode 100644 plugins/mac-virtualcam/src/obs-plugin/data/locale/sk-SK.ini create mode 100644 plugins/mac-virtualcam/src/obs-plugin/data/locale/sl-SI.ini create mode 100644 plugins/mac-virtualcam/src/obs-plugin/data/locale/sv-SE.ini create mode 100644 plugins/mac-virtualcam/src/obs-plugin/data/locale/tr-TR.ini create mode 100644 plugins/mac-virtualcam/src/obs-plugin/data/locale/uk-UA.ini create mode 100644 plugins/mac-virtualcam/src/obs-plugin/data/locale/zh-CN.ini create mode 100644 plugins/mac-virtualcam/src/obs-plugin/data/locale/zh-TW.ini create mode 100644 plugins/mac-virtualcam/src/obs-plugin/plugin-main.mm create mode 100644 plugins/mac-vth264/data/locale/kab-KAB.ini create mode 100644 plugins/obs-ffmpeg/data/locale/kab-KAB.ini create mode 100644 plugins/obs-ffmpeg/obs-ffmpeg-hls-mux.c create mode 100644 plugins/obs-ffmpeg/obs-ffmpeg-mux.h create mode 100644 plugins/obs-filters/data/locale/kab-KAB.ini create mode 100644 plugins/obs-libfdk/data/locale/kab-KAB.ini create mode 100644 plugins/obs-outputs/data/locale/kab-KAB.ini create mode 100644 plugins/obs-text/data/locale/kab-KAB.ini create mode 100644 plugins/obs-transitions/data/locale/fa-IR.ini create mode 100644 plugins/obs-transitions/data/locale/kab-KAB.ini create mode 100644 plugins/obs-x264/data/locale/kab-KAB.ini create mode 100644 plugins/oss-audio/data/locale/ar-SA.ini create mode 100644 plugins/oss-audio/data/locale/el-GR.ini create mode 100644 plugins/oss-audio/data/locale/et-EE.ini create mode 100644 plugins/oss-audio/data/locale/fa-IR.ini create mode 100644 plugins/oss-audio/data/locale/kab-KAB.ini create mode 100644 plugins/oss-audio/data/locale/pt-PT.ini create mode 100644 plugins/rtmp-services/data/locale/kab-KAB.ini create mode 100644 plugins/sndio/CMakeLists.txt create mode 100644 plugins/sndio/data/locale/ar-SA.ini create mode 100644 plugins/sndio/data/locale/ca-ES.ini create mode 100644 plugins/sndio/data/locale/cs-CZ.ini create mode 100644 plugins/sndio/data/locale/da-DK.ini create mode 100644 plugins/sndio/data/locale/de-DE.ini create mode 100644 plugins/sndio/data/locale/el-GR.ini create mode 100644 plugins/sndio/data/locale/en-GB.ini create mode 100644 plugins/sndio/data/locale/en-US.ini create mode 100644 plugins/sndio/data/locale/es-ES.ini create mode 100644 plugins/sndio/data/locale/et-EE.ini create mode 100644 plugins/sndio/data/locale/fa-IR.ini create mode 100644 plugins/sndio/data/locale/fi-FI.ini create mode 100644 plugins/sndio/data/locale/fr-FR.ini create mode 100644 plugins/sndio/data/locale/gl-ES.ini create mode 100644 plugins/sndio/data/locale/hu-HU.ini create mode 100644 plugins/sndio/data/locale/id-ID.ini create mode 100644 plugins/sndio/data/locale/it-IT.ini create mode 100644 plugins/sndio/data/locale/ja-JP.ini create mode 100644 plugins/sndio/data/locale/ka-GE.ini create mode 100644 plugins/sndio/data/locale/kab-KAB.ini create mode 100644 plugins/sndio/data/locale/ko-KR.ini create mode 100644 plugins/sndio/data/locale/nl-NL.ini create mode 100644 plugins/sndio/data/locale/pl-PL.ini create mode 100644 plugins/sndio/data/locale/pt-BR.ini create mode 100644 plugins/sndio/data/locale/pt-PT.ini create mode 100644 plugins/sndio/data/locale/ru-RU.ini create mode 100644 plugins/sndio/data/locale/sk-SK.ini create mode 100644 plugins/sndio/data/locale/sl-SI.ini create mode 100644 plugins/sndio/data/locale/sv-SE.ini create mode 100644 plugins/sndio/data/locale/tr-TR.ini create mode 100644 plugins/sndio/data/locale/uk-UA.ini create mode 100644 plugins/sndio/data/locale/zh-CN.ini create mode 100644 plugins/sndio/data/locale/zh-TW.ini create mode 100644 plugins/sndio/sndio-input.c create mode 100644 plugins/sndio/sndio-input.h create mode 100644 plugins/sndio/sndio.c create mode 100644 plugins/text-freetype2/data/locale/kab-KAB.ini create mode 100644 plugins/vlc-video/data/locale/kab-KAB.ini create mode 100644 test/cmocka/test_bitstream.c diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index bf3fbfb..c9233b5 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -23,64 +23,57 @@ jobs: name: 'macOS 64-bit' runs-on: [macos-latest] env: - MACOS_DEPS_VERSION: '2020-08-30' + MIN_MACOS_VERSION: '10.13' + MACOS_DEPS_VERSION: '2020-12-11' VLC_VERSION: '3.0.8' SPARKLE_VERSION: '1.23.0' - QT_VERSION: '5.14.1' + QT_VERSION: '5.15.2' SIGN_IDENTITY: '' steps: - name: 'Checkout' - uses: actions/checkout@v2 + uses: actions/checkout@v2.3.3 with: submodules: 'recursive' - name: 'Fetch Git Tags' run: | git fetch --prune --unshallow - echo ::set-env name=OBS_GIT_BRANCH::$(git rev-parse --abbrev-ref HEAD) - echo ::set-env name=OBS_GIT_HASH::$(git rev-parse --short HEAD) - echo ::set-env name=OBS_GIT_TAG::$(git describe --tags --abbrev=0) + echo "OBS_GIT_BRANCH=$(git rev-parse --abbrev-ref HEAD)" >> $GITHUB_ENV + echo "OBS_GIT_HASH=$(git rev-parse --short HEAD)" >> $GITHUB_ENV + echo "OBS_GIT_TAG=$(git describe --tags --abbrev=0)" >> $GITHUB_ENV - name: 'Check for Github Labels' if: github.event_name == 'pull_request' run: | LABELS_URL="$(echo ${{ github.event.pull_request.url }} | sed s'/pulls/issues/')" LABEL_FOUND="$(curl -H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" "${LABELS_URL}/labels" | sed -n 's/.*"name": "\(.*\)",/\1/p' | grep 'Seeking Testers' || true)" if [ "${LABEL_FOUND}" = "Seeking Testers" ]; then - echo ::set-env name=SEEKING_TESTERS::1 + echo "SEEKING_TESTERS=1" >> $GITHUB_ENV else - echo ::set-env name=SEEKING_TESTERS::0 + echo "SEEKING_TESTERS=0" >> $GITHUB_ENV fi - name: 'Install prerequisites (Homebrew)' shell: bash run: | - brew update --preinstall + if [ -d /usr/local/opt/openssl@1.0.2t ]; then + brew uninstall openssl@1.0.2t + brew untap local/openssl + fi + + if [ -d /usr/local/opt/python@2.7.17 ]; then + brew uninstall python@2.7.17 + brew untap local/python2 + fi brew bundle --file ./CI/scripts/macos/Brewfile - name: 'Restore Chromium Embedded Framework from cache' id: cef-cache - uses: actions/cache@v1 + uses: actions/cache@v2.1.2 env: CACHE_NAME: 'cef-cache' with: path: ${{ github.workspace }}/cmbuild/cef_binary_${{ env.CEF_BUILD_VERSION }}_macosx64 key: ${{ runner.os }}-pr-${{ env.CACHE_NAME }}-${{ env.CEF_BUILD_VERSION }} - - name: 'Restore pre-built dependencies from cache' - id: deps-cache - uses: actions/cache@v1 - env: - CACHE_NAME: 'deps-cache' - with: - path: /tmp/obsdeps - key: ${{ runner.os }}-pr-${{ env.CACHE_NAME }}-${{ env.MACOS_DEPS_VERSION }} - - name: 'Restore pre-built Qt dependency from cache' - id: deps-qt-cache - uses: actions/cache@v1 - env: - CACHE_NAME: 'deps-qt-cache' - with: - path: /tmp/obsdeps - key: ${{ runner.os }}-pr-${{ env.CACHE_NAME }}-${{ env.MACOS_DEPS_VERSION }} - name: 'Restore VLC dependency from cache' id: vlc-cache - uses: actions/cache@v1 + uses: actions/cache@v2.1.2 env: CACHE_NAME: 'vlc-cache' with: @@ -88,7 +81,7 @@ jobs: key: ${{ runner.os }}-pr-${{ env.CACHE_NAME }}-${{ env.VLC_VERSION }} - name: 'Restore Sparkle dependency from cache' id: sparkle-cache - uses: actions/cache@v1 + uses: actions/cache@v2.1.2 env: CACHE_NAME: 'sparkle-cache' with: @@ -132,10 +125,9 @@ jobs: tar -xf ./cef_binary_${{ env.CEF_BUILD_VERSION }}_macosx64.tar.bz2 -C ${{ github.workspace }}/cmbuild/ cd ${{ github.workspace }}/cmbuild/cef_binary_${{ env.CEF_BUILD_VERSION }}_macosx64 sed -i '.orig' '/add_subdirectory(tests\/ceftests)/d' ./CMakeLists.txt - # target 10.11 - sed -i '.orig' s/\"10.9\"/\"10.11\"/ ./cmake/cef_variables.cmake + sed -i '.orig' s/\"10.9\"/\"${{ env.MIN_MACOS_VERSION }}\"/ ./cmake/cef_variables.cmake mkdir build && cd build - cmake -DCMAKE_CXX_FLAGS="-std=c++11 -stdlib=libc++" -DCMAKE_EXE_LINKER_FLAGS="-std=c++11 -stdlib=libc++" -DCMAKE_OSX_DEPLOYMENT_TARGET=10.11 .. + cmake -DCMAKE_CXX_FLAGS="-std=c++11 -stdlib=libc++ -Wno-deprecated-declarations" -DCMAKE_EXE_LINKER_FLAGS="-std=c++11 -stdlib=libc++" -DCMAKE_OSX_DEPLOYMENT_TARGET=${{ env.MIN_MACOS_VERSION }} .. make -j4 mkdir libcef_dll cd ../../ @@ -144,7 +136,7 @@ jobs: run: | mkdir ./build cd ./build - cmake -DENABLE_UNIT_TESTS=YES -DENABLE_SPARKLE_UPDATER=ON -DDISABLE_PYTHON=ON -DCMAKE_OSX_DEPLOYMENT_TARGET=10.11 -DQTDIR="/tmp/obsdeps" -DSWIGDIR="/tmp/obsdeps" -DDepsPath="/tmp/obsdeps" -DVLCPath="${{ github.workspace }}/cmbuild/vlc-${{ env.VLC_VERSION }}" -DENABLE_VLC=ON -DBUILD_BROWSER=ON -DBROWSER_DEPLOY=ON -DBUILD_CAPTIONS=ON -DWITH_RTMPS=ON -DCEF_ROOT_DIR="${{ github.workspace }}/cmbuild/cef_binary_${{ env.CEF_BUILD_VERSION }}_macosx64" .. + cmake -DENABLE_UNIT_TESTS=YES -DENABLE_SPARKLE_UPDATER=ON -DDISABLE_PYTHON=ON -DCMAKE_OSX_DEPLOYMENT_TARGET=${{ env.MIN_MACOS_VERSION }} -DQTDIR="/tmp/obsdeps" -DSWIGDIR="/tmp/obsdeps" -DDepsPath="/tmp/obsdeps" -DVLCPath="${{ github.workspace }}/cmbuild/vlc-${{ env.VLC_VERSION }}" -DENABLE_VLC=ON -DBUILD_BROWSER=ON -DBROWSER_DEPLOY=ON -DWITH_RTMPS=ON -DCEF_ROOT_DIR="${{ github.workspace }}/cmbuild/cef_binary_${{ env.CEF_BUILD_VERSION }}_macosx64" .. - name: 'Build' shell: bash working-directory: ${{ github.workspace }}/build @@ -167,7 +159,7 @@ jobs: - name: 'Set Signing Identity' if: success() && startsWith(github.ref, 'refs/tags/') && github.event_name != 'pull_request' run: | - echo "::set-env name=SIGN_IDENTITY::${{ secrets.MACOS_SIGNING_IDENTITY }}" + echo "SIGN_IDENTITY=${{ secrets.MACOS_SIGNING_IDENTITY }}" >> $GITHUB_ENV - name: 'Create macOS application bundle' if: success() && (github.event_name != 'pull_request' || env.SEEKING_TESTERS == '1') working-directory: ${{ github.workspace }}/build @@ -182,7 +174,7 @@ jobs: cp rundir/RelWithDebInfo/bin/obs-ffmpeg-mux ./OBS.app/Contents/MacOS cp rundir/RelWithDebInfo/bin/libobsglad.0.dylib ./OBS.app/Contents/MacOS cp -R rundir/RelWithDebInfo/data ./OBS.app/Contents/Resources - cp ../CI/scripts/macos/app/obs.icns ./OBS.app/Contents/Resources + cp ../CI/scripts/macos/app/AppIcon.icns ./OBS.app/Contents/Resources cp -R rundir/RelWithDebInfo/obs-plugins/ ./OBS.app/Contents/PlugIns cp ../CI/scripts/macos/app/Info.plist ./OBS.app/Contents @@ -199,6 +191,7 @@ jobs: -s ./rundir/RelWithDebInfo/bin \ -x ./OBS.app/Contents/PlugIns/coreaudio-encoder.so \ -x ./OBS.app/Contents/PlugIns/decklink-ouput-ui.so \ + -x ./OBS.app/Contents/PlugIns/decklink-captions.so \ -x ./OBS.app/Contents/PlugIns/frontend-tools.so \ -x ./OBS.app/Contents/PlugIns/image-source.so \ -x ./OBS.app/Contents/PlugIns/linux-jack.so \ @@ -207,6 +200,7 @@ jobs: -x ./OBS.app/Contents/PlugIns/mac-decklink.so \ -x ./OBS.app/Contents/PlugIns/mac-syphon.so \ -x ./OBS.app/Contents/PlugIns/mac-vth264.so \ + -x ./OBS.app/Contents/PlugIns/mac-virtualcam.so \ -x ./OBS.app/Contents/PlugIns/obs-browser.so \ -x ./OBS.app/Contents/PlugIns/obs-browser-page \ -x ./OBS.app/Contents/PlugIns/obs-ffmpeg.so \ @@ -231,8 +225,8 @@ jobs: install_name_tool -id @executable_path/../Frameworks/QtNetwork.framework/Versions/5/QtNetwork ./OBS.app/Contents/Frameworks/QtNetwork.framework/Versions/5/QtNetwork install_name_tool -change /tmp/obsdeps/lib/QtCore.framework/Versions/5/QtCore @executable_path/../Frameworks/QtCore.framework/Versions/5/QtCore ./OBS.app/Contents/Frameworks/QtNetwork.framework/Versions/5/QtNetwork - sudo cp -R "${{ github.workspace }}/cmbuild/cef_binary_${{ env.CEF_BUILD_VERSION }}_macosx64/Release/Chromium Embedded Framework.framework" ./OBS.app/Contents/Frameworks/ - sudo chown -R $(whoami) ./OBS.app/Contents/Frameworks/ + cp -R "${{ github.workspace }}/cmbuild/cef_binary_${{ env.CEF_BUILD_VERSION }}_macosx64/Release/Chromium Embedded Framework.framework" ./OBS.app/Contents/Frameworks/ + chown -R $(whoami) ./OBS.app/Contents/Frameworks/ cp ../CI/scripts/macos/app/OBSPublicDSAKey.pem ./OBS.app/Contents/Resources @@ -258,6 +252,8 @@ jobs: codesign --force --options runtime --sign "${SIGN_IDENTITY:--}" "./OBS.app/Contents/Frameworks/Chromium Embedded Framework.framework/Libraries/libswiftshader_libGLESv2.dylib" codesign --force --options runtime --sign "${SIGN_IDENTITY:--}" --deep "./OBS.app/Contents/Frameworks/Chromium Embedded Framework.framework" + codesign --force --options runtime --deep --sign "${SIGN_IDENTITY:--}" "./OBS.app/Contents/Resources/data/obs-mac-virtualcam.plugin" + codesign --force --options runtime --entitlements "../CI/scripts/macos/app/entitlements.plist" --sign "${SIGN_IDENTITY:--}" --deep ./OBS.app codesign -dvv ./OBS.app @@ -268,7 +264,7 @@ jobs: run: | FILE_DATE=$(date +%Y-%m-%d) FILE_NAME=$FILE_DATE-${{ env.OBS_GIT_HASH }}-${{ env.OBS_GIT_TAG }}-macOS.dmg - echo "::set-env name=FILE_NAME::${FILE_NAME}" + echo "FILE_NAME=${FILE_NAME}" >> $GITHUB_ENV cp ../CI/scripts/macos/package/settings.json.template ./settings.json sed -i '' 's#\$\$VERSION\$\$#${{ env.OBS_GIT_TAG }}#g' ./settings.json @@ -282,7 +278,7 @@ jobs: sudo cp ./${FILE_NAME} ../nightly/${FILE_NAME} - name: 'Publish' if: success() && (github.event_name != 'pull_request' || env.SEEKING_TESTERS == '1') - uses: actions/upload-artifact@v2-preview + uses: actions/upload-artifact@v2.2.0 with: name: '${{ env.FILE_NAME }}' path: ./nightly/*.dmg @@ -294,7 +290,7 @@ jobs: FILE_DATE=$(date +%Y-%m-%d) FILE_NAME=$FILE_DATE-${{ env.OBS_GIT_HASH }}-${{ env.OBS_GIT_TAG }}-macOS.dmg RELEASE_FILE_NAME=$FILE_DATE-${{ env.OBS_GIT_HASH }}-${{ env.OBS_GIT_TAG }}-rel-macOS.dmg - echo "::set-env name=RELEASE_FILE_NAME::${RELEASE_FILE_NAME}" + echo "RELEASE_FILE_NAME=${RELEASE_FILE_NAME}" >> $GITHUB_ENV xcrun altool --store-password-in-keychain-item "AC_PASSWORD" -u "${{ secrets.MACOS_NOTARIZATION_USERNAME }}" -p "${{ secrets.MACOS_NOTARIZATION_PASSWORD }}" @@ -310,7 +306,7 @@ jobs: sudo mv ./$FILE_NAME ../release/$RELEASE_FILE_NAME - name: 'Publish Release' if: success() && startsWith(github.ref, 'refs/tags/') && github.event_name != 'pull_request' - uses: actions/upload-artifact@v2-preview + uses: actions/upload-artifact@v2.2.0 with: name: '${{ env.RELEASE_FILE_NAME }}' path: ./release/*.dmg @@ -319,24 +315,24 @@ jobs: runs-on: [ubuntu-latest] steps: - name: 'Checkout' - uses: actions/checkout@v2 + uses: actions/checkout@v2.3.3 with: submodules: 'recursive' - name: 'Fetch Git Tags' run: | git fetch --prune --unshallow - echo ::set-env name=OBS_GIT_BRANCH::$(git rev-parse --abbrev-ref HEAD) - echo ::set-env name=OBS_GIT_HASH::$(git rev-parse --short HEAD) - echo ::set-env name=OBS_GIT_TAG::$(git describe --tags --abbrev=0) + echo "OBS_GIT_BRANCH=$(git rev-parse --abbrev-ref HEAD)" >> $GITHUB_ENV + echo "OBS_GIT_HASH=$(git rev-parse --short HEAD)" >> $GITHUB_ENV + echo "OBS_GIT_TAG=$(git describe --tags --abbrev=0)" >> $GITHUB_ENV - name: 'Check for Github Labels' if: github.event_name == 'pull_request' run: | LABELS_URL="$(echo ${{ github.event.pull_request.url }} | sed s'/pulls/issues/')" LABEL_FOUND="$(curl -H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" "${LABELS_URL}/labels" | sed -n 's/.*"name": "\(.*\)",/\1/p' | grep 'Seeking Testers' || true)" if [ "${LABEL_FOUND}" = "Seeking Testers" ]; then - echo ::set-env name=SEEKING_TESTERS::1 + echo "SEEKING_TESTERS=1" >> $GITHUB_ENV else - echo ::set-env name=SEEKING_TESTERS::0 + echo "SEEKING_TESTERS=0" >> $GITHUB_ENV fi - name: Install prerequisites (Apt) shell: bash @@ -363,6 +359,7 @@ jobs: libluajit-5.1-dev \ libpulse-dev \ libqt5x11extras5-dev \ + libsndio-dev \ libspeexdsp-dev \ libswresample-dev \ libswscale-dev \ @@ -383,10 +380,12 @@ jobs: qtbase5-dev \ libqt5svg5-dev \ swig \ - libcmocka-dev + libcmocka-dev \ + linux-generic \ + v4l2loopback-dkms - name: 'Restore Chromium Embedded Framework from cache' id: cef-cache - uses: actions/cache@v1 + uses: actions/cache@v2.1.2 env: CACHE_NAME: 'cef-cache' with: @@ -404,7 +403,7 @@ jobs: run: | mkdir ./build cd ./build - cmake -DUNIX_STRUCTURE=0 -DCMAKE_INSTALL_PREFIX="${{ github.workspace }}/obs-studio-portable" -DENABLE_UNIT_TESTS=ON -DENABLE_VLC=ON -DBUILD_CAPTIONS=ON -DWITH_RTMPS=ON -DBUILD_BROWSER=ON -DCEF_ROOT_DIR="${{ github.workspace }}/cmbuild/cef_binary_${{ env.CEF_BUILD_VERSION }}_linux64" .. + cmake -DUNIX_STRUCTURE=0 -DCMAKE_INSTALL_PREFIX="${{ github.workspace }}/obs-studio-portable" -DENABLE_UNIT_TESTS=ON -DENABLE_VLC=ON -DWITH_RTMPS=ON -DBUILD_BROWSER=ON -DCEF_ROOT_DIR="${{ github.workspace }}/cmbuild/cef_binary_${{ env.CEF_BUILD_VERSION }}_linux64" .. - name: 'Build' shell: bash working-directory: ${{ github.workspace }}/build @@ -419,7 +418,7 @@ jobs: run: | FILE_DATE=$(date +%Y-%m-%d) FILE_NAME=$FILE_DATE-${{ env.OBS_GIT_HASH }}-${{ env.OBS_GIT_TAG }}-linux64.tar.gz - echo "::set-env name=FILE_NAME::${FILE_NAME}" + echo "FILE_NAME=${FILE_NAME}" >> $GITHUB_ENV cd ./build sudo checkinstall --default --install=no --pkgname=obs-studio --fstrans=yes --backup=no --pkgversion="$(date +%Y%m%d)-git" --deldoc=yes mkdir ../nightly @@ -428,7 +427,7 @@ jobs: cd - - name: 'Publish' if: success() && (github.event_name != 'pull_request' || env.SEEKING_TESTERS == '1') - uses: actions/upload-artifact@v2-preview + uses: actions/upload-artifact@v2.2.0 with: name: '${{ env.FILE_NAME }}' path: './nightly/*.tar.gz' @@ -445,20 +444,21 @@ jobs: TWITCH-HASH: ${{ secrets.TWITCH_HASH }} RESTREAM-CLIENTID: ${{ secrets.RESTREAM-CLIENTID }} RESTREAM-HASH: ${{ secrets.RESTREAM-HASH }} + VIRTUALCAM-GUID: "A3FCE0F5-3493-419F-958A-ABA1250EC20B" steps: - name: 'Add msbuild to PATH' - uses: microsoft/setup-msbuild@v1.0.0 + uses: microsoft/setup-msbuild@v1.0.2 - name: 'Checkout' - uses: actions/checkout@v2 + uses: actions/checkout@v2.3.3 with: submodules: 'recursive' - name: 'Fetch Git Tags' shell: bash run: | git fetch --prune --unshallow - echo ::set-env name=OBS_GIT_BRANCH::$(git rev-parse --abbrev-ref HEAD) - echo ::set-env name=OBS_GIT_HASH::$(git rev-parse --short HEAD) - echo ::set-env name=OBS_GIT_TAG::$(git describe --tags --abbrev=0) + echo "OBS_GIT_BRANCH=$(git rev-parse --abbrev-ref HEAD)" >> $GITHUB_ENV + echo "OBS_GIT_HASH=$(git rev-parse --short HEAD)" >> $GITHUB_ENV + echo "OBS_GIT_TAG=$(git describe --tags --abbrev=0)" >> $GITHUB_ENV - name: 'Check for Github Labels' if: github.event_name == 'pull_request' shell: bash @@ -466,13 +466,13 @@ jobs: LABELS_URL="$(echo ${{ github.event.pull_request.url }} | sed s'/pulls/issues/')" LABEL_FOUND="$(curl -H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" "${LABELS_URL}/labels" | sed -n 's/.*"name": "\(.*\)",/\1/p' | grep 'Seeking Testers' || true)" if [ "${LABEL_FOUND}" = "Seeking Testers" ]; then - echo ::set-env name=SEEKING_TESTERS::1 + echo "SEEKING_TESTERS=1" >> $GITHUB_ENV else - echo ::set-env name=SEEKING_TESTERS::0 + echo "SEEKING_TESTERS=0" >> $GITHUB_ENV fi - name: 'Restore QT dependency from cache' id: qt-cache - uses: actions/cache@v1 + uses: actions/cache@v2.1.2 env: CACHE_NAME: 'windows-qt-cache' with: @@ -480,7 +480,7 @@ jobs: key: ${{ runner.os }}-pr-${{ env.CACHE_NAME }}-${{ env.QT_VERSION }} - name: 'Restore pre-built dependencies from cache' id: deps-cache - uses: actions/cache@v1 + uses: actions/cache@v2.1.2 env: CACHE_NAME: 'windows-deps-cache' with: @@ -488,7 +488,7 @@ jobs: key: ${{ runner.os }}-pr-${{ env.CACHE_NAME }}-${{ env.WINDOWS_DEPS_VERSION }} - name: 'Restore VLC dependency from cache' id: vlc-cache - uses: actions/cache@v1 + uses: actions/cache@v2.1.2 env: CACHE_NAME: 'windows-vlc-cache' with: @@ -496,7 +496,7 @@ jobs: key: ${{ runner.os }}-pr-${{ env.CACHE_NAME }}-${{ env.VLC_VERSION }} - name: 'Restore CEF dependency from cache (64 bit)' id: cef-cache - uses: actions/cache@v1 + uses: actions/cache@v2.1.2 env: CACHE_NAME: 'windows-cef-64-cache' with: @@ -527,7 +527,7 @@ jobs: mkdir ./build mkdir ./build64 cd ./build64 - cmake -G"${{ env.CMAKE_GENERATOR }}" -A"x64" -DCMAKE_SYSTEM_VERSION="${{ env.CMAKE_SYSTEM_VERSION }}" -DBUILD_BROWSER=true -DBUILD_CAPTIONS=true -DCOMPILE_D3D12_HOOK=true -DVLCPath="${{ github.workspace }}/cmbuild/vlc" -DDepsPath="${{ github.workspace }}/cmbuild/deps/win64" -DQTDIR="${{ github.workspace }}/cmbuild/QT/${{ env.QT_VERSION }}/msvc2017_64" -DENABLE_VLC=ON -DCEF_ROOT_DIR="${{ github.workspace }}/cmbuild/cef_binary_${{ env.CEF_VERSION }}_windows64_minimal" -DCOPIED_DEPENDENCIES=FALSE -DCOPY_DEPENDENCIES=TRUE .. + cmake -G"${{ env.CMAKE_GENERATOR }}" -A"x64" -DCMAKE_SYSTEM_VERSION="${{ env.CMAKE_SYSTEM_VERSION }}" -DBUILD_BROWSER=true -DCOMPILE_D3D12_HOOK=true -DVLCPath="${{ github.workspace }}/cmbuild/vlc" -DDepsPath="${{ github.workspace }}/cmbuild/deps/win64" -DQTDIR="${{ github.workspace }}/cmbuild/QT/${{ env.QT_VERSION }}/msvc2017_64" -DENABLE_VLC=ON -DCEF_ROOT_DIR="${{ github.workspace }}/cmbuild/cef_binary_${{ env.CEF_VERSION }}_windows64_minimal" -DCOPIED_DEPENDENCIES=FALSE -DCOPY_DEPENDENCIES=TRUE -DVIRTUALCAM_GUID=${{ env.VIRTUALCAM-GUID }} .. - name: 'Build' run: msbuild /m /p:Configuration=RelWithDebInfo .\build64\obs-studio.sln - name: 'Package' @@ -535,16 +535,15 @@ jobs: run: | $env:FILE_DATE=(Get-Date -UFormat "%F") $env:FILE_NAME="${env:FILE_DATE}-${{ env.OBS_GIT_HASH }}-${{ env.OBS_GIT_TAG }}-win64.zip" - echo "::set-env name=FILE_NAME::${env:FILE_NAME}" + echo "FILE_NAME=${env:FILE_NAME}" >> ${env:GITHUB_ENV} robocopy .\build64\rundir\RelWithDebInfo .\build\ /E /XF .gitignore 7z a ${env:FILE_NAME} .\build\* - name: 'Publish' if: success() && (github.event_name != 'pull_request' || env.SEEKING_TESTERS == '1') - uses: actions/upload-artifact@v2-preview + uses: actions/upload-artifact@v2.2.0 with: name: '${{ env.FILE_NAME }}' path: '*-win64.zip' - win32: name: 'Windows 32-bit' runs-on: [windows-latest] @@ -557,20 +556,21 @@ jobs: TWITCH-HASH: ${{ secrets.TWITCH_HASH }} RESTREAM-CLIENTID: ${{ secrets.RESTREAM-CLIENTID }} RESTREAM-HASH: ${{ secrets.RESTREAM-HASH }} + VIRTUALCAM-GUID: "A3FCE0F5-3493-419F-958A-ABA1250EC20B" steps: - name: 'Add msbuild to PATH' - uses: microsoft/setup-msbuild@v1.0.0 + uses: microsoft/setup-msbuild@v1.0.2 - name: 'Checkout' - uses: actions/checkout@v2 + uses: actions/checkout@v2.3.3 with: submodules: 'recursive' - name: 'Fetch Git Tags' shell: bash run: | git fetch --prune --unshallow - echo ::set-env name=OBS_GIT_BRANCH::$(git rev-parse --abbrev-ref HEAD) - echo ::set-env name=OBS_GIT_HASH::$(git rev-parse --short HEAD) - echo ::set-env name=OBS_GIT_TAG::$(git describe --tags --abbrev=0) + echo "OBS_GIT_BRANCH=$(git rev-parse --abbrev-ref HEAD)" >> $GITHUB_ENV + echo "OBS_GIT_HASH=$(git rev-parse --short HEAD)" >> $GITHUB_ENV + echo "OBS_GIT_TAG=$(git describe --tags --abbrev=0)" >> $GITHUB_ENV - name: 'Check for Github Labels' if: github.event_name == 'pull_request' shell: bash @@ -578,13 +578,13 @@ jobs: LABELS_URL="$(echo ${{ github.event.pull_request.url }} | sed s'/pulls/issues/')" LABEL_FOUND="$(curl -H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" "${LABELS_URL}/labels" | sed -n 's/.*"name": "\(.*\)",/\1/p' | grep 'Seeking Testers' || true)" if [ "${LABEL_FOUND}" = "Seeking Testers" ]; then - echo ::set-env name=SEEKING_TESTERS::1 + echo "SEEKING_TESTERS=1" >> $GITHUB_ENV else - echo ::set-env name=SEEKING_TESTERS::0 + echo "SEEKING_TESTERS=0" >> $GITHUB_ENV fi - name: 'Restore QT dependency from cache' id: qt-cache - uses: actions/cache@v1 + uses: actions/cache@v2.1.2 env: CACHE_NAME: 'qt-cache' with: @@ -592,7 +592,7 @@ jobs: key: ${{ runner.os }}-pr-${{ env.CACHE_NAME }}-${{ env.QT_VERSION }} - name: 'Restore pre-built dependencies from cache' id: deps-cache - uses: actions/cache@v1 + uses: actions/cache@v2.1.2 env: CACHE_NAME: 'deps-cache' with: @@ -600,7 +600,7 @@ jobs: key: ${{ runner.os }}-pr-${{ env.CACHE_NAME }}-${{ env.WINDOWS_DEPS_VERSION }} - name: 'Restore VLC dependency from cache' id: vlc-cache - uses: actions/cache@v1 + uses: actions/cache@v2.1.2 env: CACHE_NAME: 'vlc-cache' with: @@ -608,7 +608,7 @@ jobs: key: ${{ runner.os }}-pr-${{ env.CACHE_NAME }}-${{ env.WINDOWS_VLC_VERSION }} - name: 'Restore CEF dependency from cache (32 bit)' id: cef-cache - uses: actions/cache@v1 + uses: actions/cache@v2.1.2 env: CACHE_NAME: 'cef-32-cache' with: @@ -639,7 +639,7 @@ jobs: mkdir ./build mkdir ./build32 cd ./build32 - cmake -G"${{ env.CMAKE_GENERATOR }}" -A"Win32" -DCMAKE_SYSTEM_VERSION="${{ env.CMAKE_SYSTEM_VERSION }}" -DENABLE_VLC=ON -DBUILD_BROWSER=true -DBUILD_CAPTIONS=true -DCOMPILE_D3D12_HOOK=true -DVLCPath="${{ github.workspace }}/cmbuild/vlc" -DDepsPath="${{ github.workspace }}/cmbuild/deps/win32" -DQTDIR="${{ github.workspace }}/cmbuild/QT/${{ env.QT_VERSION }}/msvc2017" -DCEF_ROOT_DIR="${{ github.workspace }}/cmbuild/cef_binary_${{ env.CEF_VERSION }}_windows32_minimal" -DCOPIED_DEPENDENCIES=FALSE -DCOPY_DEPENDENCIES=TRUE .. + cmake -G"${{ env.CMAKE_GENERATOR }}" -A"Win32" -DCMAKE_SYSTEM_VERSION="${{ env.CMAKE_SYSTEM_VERSION }}" -DENABLE_VLC=ON -DBUILD_BROWSER=true -DCOMPILE_D3D12_HOOK=true -DVLCPath="${{ github.workspace }}/cmbuild/vlc" -DDepsPath="${{ github.workspace }}/cmbuild/deps/win32" -DQTDIR="${{ github.workspace }}/cmbuild/QT/${{ env.QT_VERSION }}/msvc2017" -DCEF_ROOT_DIR="${{ github.workspace }}/cmbuild/cef_binary_${{ env.CEF_VERSION }}_windows32_minimal" -DCOPIED_DEPENDENCIES=FALSE -DCOPY_DEPENDENCIES=TRUE -DVIRTUALCAM_GUID=${{ env.VIRTUALCAM-GUID }} .. - name: 'Build' run: msbuild /m /p:Configuration=RelWithDebInfo .\build32\obs-studio.sln - name: 'Package' @@ -647,12 +647,12 @@ jobs: run: | $env:FILE_DATE=(Get-Date -UFormat "%F") $env:FILE_NAME="${env:FILE_DATE}-${{ env.OBS_GIT_HASH }}-${{ env.OBS_GIT_TAG }}-win32.zip" - echo "::set-env name=FILE_NAME::${env:FILE_NAME}" + echo "FILE_NAME=${env:FILE_NAME}" >> ${env:GITHUB_ENV} robocopy .\build32\rundir\RelWithDebInfo .\build\ /E /XF .gitignore 7z a ${env:FILE_NAME} .\build\* - name: 'Publish' if: success() && (github.event_name != 'pull_request' || env.SEEKING_TESTERS == '1') - uses: actions/upload-artifact@v2-preview + uses: actions/upload-artifact@v2.2.0 with: name: '${{ env.FILE_NAME }}' path: '*-win32.zip' diff --git a/AUTHORS b/AUTHORS index dc8f461..3656342 100644 --- a/AUTHORS +++ b/AUTHORS @@ -284,34 +284,38 @@ Translators: - ZILZAL - Abdullah AL-Qahtani (Za7ef_SA) - majdcomp - - aaakjt - Tareq Almutairi (Tareq_s) + - aaakjt + - AiAF (7MR) - ibrahim younis (sintorea_incyx) - معتصم دعنا (rozana-media) - Mohamed Zain (Thecheeseman) - Gol D. Ace (goldace) - Vainock - Saleh oukiki (salehoukiki) + - Ahmad Alkurbi (DontPlay) - Tensai - Mustafa2018 - BeleganStartup - Ndalabo Taema (hake_bsowq) - - Ahmad Alkurbi (DontPlay) + - Fahad Alshaya (fashaya) - Hani Sweileh (hno.sweileh) - - BWU Wheelman (Wheelman) - Nasser Bin Laboun (nasserbinlaboun) + - BWU Wheelman (Wheelman) - FC Barcelona HD (kurdnews) - osmansalih (hpcplus2016) - - unknowndomain - Yhea Ahmad (yhea.ahmad7741) + - unknowndomain - Ahmed Hawam (Hawam) - Mnsor The-Ghost (mnsor1722011) - Malaz Gold Edition (Malo7zz) - dodgepong - chaironeko - Hadi Gamer (hadigamer3131) + Aragonese: + - juanpabl Azerbaijani: - - Shahin Farzaliyev (Khan27) + - ShahinF27 (Khan27) - Javid-An - unknowndomain - Kənan Axundov (kenanaxundov2) @@ -325,16 +329,18 @@ Translators: - Xabier Aramendi (azpidatziak) - Osoitz - Gol D. Ace (goldace) + - Sergio Varela (IngrownMink4) - Vainock - EG Gamer (eggamer131) - txaro - etxondoko - unknowndomain + - Fiwi1265 - dodgepong - - jolaus - - alaitzgabi - - ziztazale - zientek + - alaitzgabi + - jolaus + - ziztazale Bengali: - shamuntohamd - Rudro Rasel (rdrrsl) @@ -350,7 +356,7 @@ Translators: - Zakxaev68 - kalmarin - Seyhan Halil (yildirim17) - - Martin Georgiev (DivideByNone) + - DivideByNone - Vainock - Viktor Kitov (viktorkitov) - djradimix @@ -363,6 +369,8 @@ Translators: - Salif Mehmed (salifm) - Warchamp7 - dodgepong + Burmese: + - linwinthu Catalan: - Jaime Muñoz Martín (jmmartin_5) - Benet R. i Camps (BennyBeat) (BennyBeat) @@ -374,6 +382,7 @@ Translators: - Gol D. Ace (goldace) - jan (test83318) - vilagamer999 + - Xavier Muntada Samà (XavierMSama) - Pere O. (gotrunks) - unknowndomain - Adolfo Jayme (fitoschido) @@ -399,8 +408,8 @@ Translators: - cai_miao - Opportunity (OpportunityLiu) - MarsYoung - - Inku Xuan (inkuxuan) - SR_Mango + - Inku Xuan (inkuxuan) - Yi-Jyun Pan (pan93412) - yunluzhang - copyliu @@ -443,13 +452,15 @@ Translators: - Watson Tsai (ashaneba) - Han-Jen Cheng (notexist) - Inndy.Lin (inndy) + - offthegrid-mike - khng300 - abc0922001 - - ak-47root - Meng Hao Li (GazCore) + - ak-47root - Edison Lee (edisonlee55) - Append Huang (append) - fangzheng + - yeft - zhtw - JackYeah - unknowndomain @@ -460,18 +471,18 @@ Translators: - FaZe Fakay (fazefakay) - chaironeko - tomoe-musashi + - Tatsujin (c910335) + - Bob Wei (BobWaver) + - Tommy Chiang (oToToT) - watadon - WeingHong - - Bob Wei (BobWaver) - - Tatsujin (c910335) - - Tommy Chiang (oToToT) Croatian: - medicmomcilo - srdjan_m - Fran Kelava (fkelava) + - schwabengeiz - Runicar (dajtisina) - Wildrage - - schwabengeiz - penta (junp5i) - OfficialwobY - Gol D. Ace (goldace) @@ -486,18 +497,19 @@ Translators: - Matěj Kozák (GrrrandyCZ) - Kryštof Černý (cleverline1mc) - Vainock + - X3r1k (x3r1k) - Stewio MC (stepandolsky) - Gol D. Ace (goldace) - JIMMY (vopasek) - Kiznoh - Sawanyo - - MrJaroslavik#8412 (MJaroslavik) + - MrJaroslavik - TheWolfiKK - - Erik Bročko (ericek111) - unknowndomain - - dodgepong - - Martin Pilát (piltmartin) + - Erik Bročko (ericek111) - Daniel Padrta (dpadrta) + - Martin Pilát (piltmartin) + - dodgepong - Jáchym Plánička (Jacerros) Danish: - NCAA @@ -521,19 +533,20 @@ Translators: - Mytologi Dutch: - Eric Bataille (ThoNohT) + - A. Voogt (atvoogt) - Michel Snippe (michelsnippe) - Greendweller - exeldro - Albakham (albakham) - - Coen (Trigstur) - Lars Acou (lars.acou) + - Coen (Trigstur) - Danny (Dkamps18) - Richard Stanway (r1ch) + - Harm van den Hoek (harm27) - Nicole (Dutchess_Nicole) - robbert0891 (robbertoorschot38) - Gol D. Ace (goldace) - Kjetil Verstrepen (kjetilv) - - Harm van den Hoek (harm27) - Jasper J (JassieJ) - Vainock - b__dm @@ -545,6 +558,7 @@ Translators: - andymidside - F_Producktions - Thom Knepper (MrKnepp) + - Lesley Natrop (lesleynatrop) - Bo Alsemgeest (bo.alsemgeest.wausie) - lokerhp - unknowndomain @@ -563,24 +577,27 @@ Translators: - Noah Husby (noahhusby) - Endysis - Pete Russell (pete.russell.photos) + Esperanto: + - Matt Aaldenberg (MattAalden) + - Vainock Estonian: - MartinEwing - Oliver Jõgar (treier57lol) (difiter23) - AndresTraks + - Agu Ratas (aguratas) - C3kos (C3kos1) - Gol D. Ace (goldace) - unknowndomain - Vainock - - Agu Ratas (aguratas) Filipino: - dwaeji-aizelle - nyakayed - - Loyd Stephen Jayme (loydjayme25) - CodeYan01 + - Loyd Stephen Jayme (loydjayme25) - jermel + - Raffy (Tested) - Gol D. Ace (goldace) - Vainock - - Raffy (Tested) - arnoldsecret - Raylir - unknowndomain @@ -592,8 +609,8 @@ Translators: - dodgepong - Tero Keso (tero.keso) - Gol D. Ace (goldace) - - Pyscowicz - Vainock + - Pyscowicz - Obama (Obama44) - unknowndomain - Ville Närhi (daimaah) @@ -606,10 +623,10 @@ Translators: - Tocram2 (tocram2) - Benjamin Cambour (lesinfox) - Yberion + - Guillaume Turchini (orion78fr) - Léo (leeo97one) - RisedSky (THEMINECRAFT951) - Pikana - - Guillaume Turchini (orion78fr) - BoboopTeam - DoK_- - DarckCrystale @@ -618,8 +635,8 @@ Translators: - DarkInFire - Theguiguix - Gol D. Ace (goldace) - - Vainock - Youtubeur FR│Giaco35 (Giaco35) + - Vainock - steve_fr - kyllian (tardigradeus) - Deski_ @@ -627,11 +644,13 @@ Translators: - Aime23 - Grisou2907 - BaguetteDePain_ + - Anat ROCHUT (arochut) - Keter LordFR (YorHaDen) - Jérémy LITIQUE (JeremyLTE) - illusdidi - - 🌠 DarK | #Hello 🌠 (DarKTV_FR) - Mathieu Hautebas (matteyeux) + - 🌠 DarK | #Hello 🌠 (DarKTV_FR) + - christophe (TedM) - Yolopix - Gabriel Dugny (Gabigabigo) - tburette @@ -643,20 +662,25 @@ Translators: - Alexis Brandner (Alexinfos) - Camille Nury (kamsdu30) - dodgepong - - Lexane Sirac (Exilexi) - Jean-Mathieu Jm Samson (sjm450666) - - Albakham (albakham) + - Lexane Sirac (Exilexi) + - Wizi_89 - HistoriCode97 - - Warchamp7 + - Albakham (albakham) - SkylixX - - chaironeko + - Warchamp7 - Lucas Juif (trycarnage) - - William Dunn (williamdunnperso) - - Marc André Audet (Manhim) - - HoPollo (HoPolloTV) + - chaironeko + - RuruDuTurfu_ + - Antwan - E Ju (enuajenuaj) - Parfum - - Antwan + - HoPollo (HoPolloTV) + - William Dunn (williamdunnperso) + - Isa (isabellez_bp) + - Skew (noan.perrot) + - Marc André Audet (Manhim) + - FauconSpartiate Galician: - mbouzada - Xesús M. Mosquera Carregal (xesusmosquera) @@ -664,6 +688,7 @@ Translators: - Vainock - Gol D. Ace (goldace) - unknowndomain + - HexaTree (nightcamel) - chaironeko - aluaces - dodgepong @@ -675,8 +700,8 @@ Translators: - Gol D. Ace (goldace) - unknowndomain German: - - Gol D. Ace (goldace) - Vainock + - Gol D. Ace (goldace) - Michael Fabian Dirks (Xaymar) - Sven Kirschbaum (fallobst22) (fallobst22) - Gregor Bigalke (gregtcltk) @@ -708,7 +733,6 @@ Translators: - Hadi Gamer (hadigamer3131) - degra78 (degra789) - Tiim - - Dominik Weissenseel (domisum) - Lasse Niermann (TheLasseHD) - Elementies - Fabian Küntzler (tringlp) @@ -728,14 +752,15 @@ Translators: - Scourgemcdak - Mepharees - Pigot :P (pigot715) + - TheMetalHelper - Tasos Sahanidis (tatokis) - George T. (tzikas97) - Vainock - Alex Kalles (alexakis1997) + - Ανδρέας Γεωργόπουλος (andrewgeo) - Kostas F (Kostas-F) - Warmaster - Gol D. Ace (goldace) - - Ανδρέας Γεωργόπουλος (andrewgeo) - iosifidis - Giorgos (bigdiskboi) - Themis T. (Deminho) @@ -750,21 +775,23 @@ Translators: - lonelywolf11 - djsavta - Omeritzics Games (omeritzicschwartz) + - idanbo27 + - עידו דנה (idodana01) - nachmanpop - Vainock - Yotam Ziv (yotamziv87) - - עידו דנה (idodana01) - Chemi - Gol D. Ace (goldace) - Light1c3 - Yoel (ye8323) - epic_ziver_D - Netro (roi_adler) + - Hilla Glebotzki (Hilla123) - TheOver (upmeboost) - unknowndomain - yair (5shekel) - - אפיק רוזנר (afikr333) - ghsi + - אפיק רוזנר (afikr333) - Tal Machani (talmachani) Hindi: - Saswata Banerjee (azure.saswata) @@ -773,6 +800,7 @@ Translators: - SneakyFish5 - shamuntohamd - unknowndomain + - Vainock - Gol D. Ace (goldace) Hungarian: - Gige @@ -780,12 +808,15 @@ Translators: - Gol D. Ace (goldace) - Sárga Pulcsis (SargaPulcsis) - sarkanyka444 + - zolikonta - Vainock - Dániel P. (Daniii_) - Balázs Meskó (meskobalazs) - TOM005 + - Isti (eisti) - Adam Liszkai (adamos42) - vargag159 + - Biró Bence (birobence19) - unknowndomain - abydosan (abydoshun) - dodgepong @@ -794,12 +825,13 @@ Translators: - EzigboOmenana Indonesian: - M Akmal (akmalcakep59) + - Rafy Shafryan (NexaForX) + - Anbiya Shafaat (Anfia) - Rendi (rendiazmi) - ziasukmana - GudankGaming GG (GudankGaming) - Vainock - Lieba Natur Brilian (naturbrilian) - - Anbiya Shafaat (Anfia) - doplank - unknowndomain Italian: @@ -816,6 +848,7 @@ Translators: - Alessandro Sarto (alesarto03) - Tommaso Cammelli (tomganguz) (tomganguz) - mauriziopersi + - Marco Ciampa (ciampix) - Martazza - ScemEnzo - Christian Mazzola (_Alpha06) @@ -835,15 +868,16 @@ Translators: - SkyLion - Asbesbopispa - unknowndomain + - Benedetto Mazza (benedetto.mazza99) - Owly - Federico Tensi (habby1337) - NightMat - Daniele02_777 - Alessandro Iepure (alessandro_iepure) - Flavio Rinaldi (flaviorinaldi) - - Alessandro Levante (lallo2401) - Valerio Ragni (ragni.valerio) - Marco Scardovi (ScardracS) + - Alessandro Levante (lallo2401) - Umberto Croci (umbertolb) Japanese: - shousa @@ -866,7 +900,11 @@ Translators: - Yuki Yu (Yukiyu) - TH_238 - Teimu Tekura (diglateam3) + Kabyle: + - Yacine Bouklif (YacineBouklif) + - Selyan Slimane AMIRI (slimane_AMIRI) Khmer: + - thuonmohasal (thuon-mohasal) - ប៉ុកណូ រ៉ូយ៉ាល់ (poknoroyal68) - បងមាន តែអូន (cheaiphone267) - Gol D. Ace (goldace) @@ -875,12 +913,15 @@ Translators: - Alex Lee (alex01763) - Vainock - Gol D. Ace (goldace) + - AlexKoala (alexkoala) - RedditRook - Jong Kwon Choi (dailypro) - Ra.Workspace (RaWouk) + - hykdem kim (hykdem) - Russell (crimeroyal) - unknowndomain - Charles Wallis (charlestw127) + - Tristar Corp (Charleslee) - antome - 김동현 (ehehguu) - dodgepong @@ -889,11 +930,13 @@ Translators: - Vainock - RanjdarAbdulrazzaq - Aga Mangure (agaesmaeel) + Lao: + - nirankoon.singpraseuth (nirankoon) Lithuanian: - Justas Vilimas (tyntas) - xNaii (lyrikas5) - - Rolic - TitasK (titukas1572) + - Rolic - dnew (dbot) - unknowndomain - Gol D. Ace (goldace) @@ -908,7 +951,7 @@ Translators: - dodgepong Mongolian: - begjan - - Bilguun Ochirbat (Bil0203) + - Bilguun Ochirbat (BilguunOch) - unknowndomain - Vainock - Gol D. Ace (goldace) @@ -921,11 +964,12 @@ Translators: - dodgepong - LandyLERThERmfLOpi - areedw + - flaeri - mgKaiztra - Tommy (nwgat) - Vainock - - Jordan Stutzmann (J-Stutzmann) - Syver Stensholt (sssandum) + - Jordan Stutzmann (J-Stutzmann) - Alex Thomassen (Decicus) - Sander Skjegstad (r530er) - Gol D. Ace (goldace) @@ -944,15 +988,20 @@ Translators: - Yngve Spjeld Landro (yslandro) - Gol D. Ace (goldace) Persian: + - Kiper King (kiperking1) - koper - MZ MAXIMUM (mahdigamermax) - - Alireza Firouzi (pikhoshorg) + - Pikhosh (pikhoshorg) - peymanr34 - Vainock + - Mohammad jawad (mrahmani788) + - Farshid Meidani (farshid_mi) - Gol D. Ace (goldace) - KinxShar (yasharaminasghari6) - Berrely - unknowndomain + - alefvanoon + - nohaxjustoof - Amirhossein yousefi (amir.sara) - Navid Sadeghieh (nsadeghieh) Pirate English: @@ -972,12 +1021,13 @@ Translators: - iltrof - Berrely - Lol Wut (OldGrandmaFarts) - - chaironeko - ncb + - chaironeko - MaltahlGaming (maltahlgaming) - Redback93 - Mepharees - kkartaltepe + - KennanHunter Polish: - Tomasz 'grocal' Grodzki (grocal) - Albakham (albakham) @@ -997,6 +1047,7 @@ Translators: - Michal (progamesmicrok) - unknowndomain - Piteriuz + - mjluszko - dodgepong - Julia Drewniak (ewagsi) - Patryk Kunda (ner.i.ol) @@ -1007,6 +1058,7 @@ Translators: Portuguese: - Ev1lbl0w - joaofvieira + - Rui Machado (polystation4) - Manuela Silva (mansil) - André Biscaia (LazP) - Tomás Antunes (tomasantunes) @@ -1016,49 +1068,58 @@ Translators: - alexandre433 - Vainock - pedro.moreira.359 (pmmorsoft) + - Nuno Matos (NunoCMatos) - Gol D. Ace (goldace) + - vanscorp + - Gatinhos - Gabriel L. (realgabriell) - Diogo Soares (DabliwAga) + - kayal15948 - unknowndomain - - Tiago Mesquita (tiagomesquita) - Gost_Evil + - Tiago Mesquita (tiagomesquita) Portuguese, Brazilian: - Shaolin (admshao) + - Diogo Ramos (dr03ramos) - Ramon Mendes (rbrgameplays) - Fabio Madia (Shaolin) - Burkes - Guilherme Dias (Darkaiser) - Emanoel Lopes (emanoelopes) - - TFSThiagoBR98 - Lincoln H. (LincolnH) + - TFSThiagoBR98 - Vainock - CaioWzy - mizifih - André Gama (ToeOficial) + - Skellingtor - Avellar (BetaTester) - ドージェ (Doges) - clr0dr1g - aalonsomb - Gol D. Ace (goldace) - LoboMetalurgico - - Pragmata - - maribatis + - mathues + - Maneschy - lakitoo - - João (fror) + - maribatis + - igorruckert - DevilLorde + - João (fror) - unknowndomain - - Ramon Gonzalez (ramon200000) - Esdras Tarsis (esdrastarsis) + - Ramon Gonzalez (ramon200000) + - Guilherme Cruz (gcrz) - dodgepong + - Finhawk - andre.krdoso - dlageBR - park (TheBugMeNot) - - Finhawk - - Guilherme Cruz (gcrz) + - ghklug - Tiago Danin (TiagoDanin) - - sauloleite_quim - hakimgrr - Eliezer de Almeida (Eliezer62) + - sauloleite_quim Punjabi: - manjotsingh0202 - unknowndomain @@ -1074,7 +1135,7 @@ Translators: - Mihai G (babasghenciu) - Vainock - Gol D. Ace (goldace) - - Johnthenoone + - Melonoone - AlexTheDacian - Diamyx - unknowndomain @@ -1087,8 +1148,8 @@ Translators: - iltrof - Andrei Stepanov (adem4ik) - Pavel (Shevalie) - - VNGXR - EDNVKjldr8vyu9 + - VNGXR - Bugo - MaximGribanov - dodgepong @@ -1098,6 +1159,7 @@ Translators: - Runoff Screen (glebpozbnakov62) - Artem4ik - Yaroslav (MrYadro) + - HexaTree (nightcamel) - Пахомов Александр (GXTrus) - fromgate - Synbulat Biishev (Syjalo) @@ -1106,6 +1168,7 @@ Translators: - Andy (anry025) - er123rin (se123rin) - Nemesis (Nemesis07) + - bxkr - Serge Sklyarov (sergesklyarov) - Андрей Курдюков (sandrix) - Makatavin # (makatavin0) @@ -1117,41 +1180,45 @@ Translators: - RaspingMango (RaspingMango637) - Myasko - Mixaill - - Иван Геймеров (hronos-2t) - Super 2004 (pe86ki) + - Иван Геймеров (hronos-2t) - Nikita Bibanaev (nicky18013) - - Sergei Fug1t1v3 (fug) - Максим Куренков (kuplay) - - Цезарь Ролл (vanessik78) + - Sergei Fug1t1v3 (fug) + - Цезарь Ролл (CeaserRoll) - Walt Gee (vovanych) - - bxkr - - unknowndomain - zy9c 1337 (zy9c228) + - unknowndomain + - Илья Кузнецов (ilyavj) + - Ninja Hacker3000 (ninjahacker3875) - allan walpy (AndreyLysenkov) - Drahonn - SandoBY - - Mr. Games (oohskofgs) - - Yuri Mihaqlov (yurijmi) - Meldone (meldone) + - BeDubber + - Yuri Mihaqlov (yurijmi) + - Mr. Games (oohskofgs) - Anatoly (Atsupak) - Kcurett TM (thekcurett) + - Leika098 + - Sigge Stjärnholm (Kladdy) + - iLefty - TR1D - TOWUK (towuk118) - Evgeny Bogdanov (vtrifonov548) - - iLefty - - Sigge Stjärnholm (Kladdy) - - Kuji Kitamura (KujiKita) + - MUHADDIS MEDIA (muhaddismedia) - MeoWStraY - Kirill Arkhipov (dokl957) - - MUHADDIS MEDIA (muhaddismedia) + - Kuji Kitamura (KujiKita) + - hoserfx + - Sam Vo (samvo) + - chaironeko + - Юрій (Devinit) - Milise_Tailise - The ZedIvan (ZedIvan) + - L1Q - Churikov Radmir Sergeevich (RadMir2) - Sasha Sorokin (Sasha-Sorokin) - - Юрій (Devinit) - - chaironeko - - L1Q - - Sam Vo (samvo) Scottish Gaelic: - GunChleoc - Vainock @@ -1200,6 +1267,7 @@ Translators: Slovenian: - Arnold Marko (atomicmind) - kristjan.krusic (krusic22) + - admrs - Aleksander Kovač (Acookook) - MG lolenstine (mglolenstine) - Vainock @@ -1223,9 +1291,10 @@ Translators: - Pilar G. (TheMadnessLady) - Gol D. Ace (goldace) - Lluís R (LluisR98) + - MarioMey + - Manuel Matías (manuel.matias) - Vainock - Maximiliano Schtroumpftech Pena-Roig (som2tokmynam) - - MarioMey - Pakotoyako - Carlos Plata (carlosesgenial33) - eemiroj @@ -1233,6 +1302,7 @@ Translators: - Skiddome (sergiomalagonmartin) - Marcos Vidal (markitos.maki22) - Ruben Deig Ramos (rdeigramos) + - Roriita - Ray (Ipsumry) - makiza1 (micosil_2) - Santiago Pereyra (SannttVIII) @@ -1240,14 +1310,15 @@ Translators: - David Sonico (davidsubsonico) - Eleazar (MtrElee3) - amssusgameplays (willifake052) - - Adolfo Jayme (fitoschido) + - D E B (D_E_B) - Jaire (corpi.98) + - Adolfo Jayme (fitoschido) - Sigge Stjärnholm (Kladdy) - unknowndomain - dodgepong - Rodrigo Ipince (ipince) - - Gloriana Cocozza (gcocozza) - chaironeko + - Gloriana Cocozza (gcocozza) - Mogabie's Nation (Mogabie) - Rubén Pérez (RixzZ) - Stuttero @@ -1262,12 +1333,15 @@ Translators: - 0x9fff00 - Gustav Ekner (ekner) - Vainock + - Victor Ahlin (VSwede) - Jonatan Nyberg (sweuser) + - Mats Karlsson (matska) - ArvidTheSwe - Olle Dahström (odahlstrom) - Gol D. Ace (goldace) - - unknowndomain - Henrik Mattsson-Mårn (rchk) + - unknowndomain + - Axel Aminoff (axel.aminoff) - chaironeko - Jonas Svensson (jonassanojj99) - Hannes Blåman (thebluis) @@ -1291,18 +1365,21 @@ Translators: Tamil: - anto27 - Jaiganesh Kumaran (Jaiganesh) + - rooban23 - Gol D. Ace (goldace) - Vainock - unknowndomain Thai: - Nawin Somprasong (thaipirch98) - - ธีรภัทร์ โยชนา (Gataro) + - zero0200 + - ธีรภัทร์ โยชนา (2RD) - sakuhanachan* (sakuhanachanloli) - SurachaiJUI - Sakia Normal Human (arcanaarcana5) - PolaX3 - nongnoobjung (kitcharuk_4) - 盛凤阁 (execzero) + - Rathchaarnon Threeanjuleethaan (rathchaarnon) - unknowndomain - แมน ทศพร (lovemanna456) - Vainock @@ -1318,16 +1395,19 @@ Translators: - Savas Tokmak (Laserist) - Umut kılıç (kilic190787) - vgezer - - furkanbicici - - Murat Karagöz (anemon_1994) - Vainock + - furkanbicici + - keke_ea + - Murat Karagöz (anemon_1994) - Bilgehan Demirel (bilgehandemirel) - Gol D. Ace (goldace) - - berkcan uçan (ibnehayati) - Alperen Yıldız (Sparrow34) + - berkcan uçan (ibnehayati) + - Solusyon2 - gecebekcisi1 - - Furkan Korhan (furkankorhan) - Emin Can OGUZ (emincanoguz11) + - Furkan Korhan (furkankorhan) + - Ege (ekto) - Onur Yılmaz (Makaron3422) - mustafaa - Richard Stanway (r1ch) @@ -1341,7 +1421,9 @@ Translators: - Fatih Güneş (fatihgunes) - Türker Yıldırım (turkeryildirim) - basakbk + - Yıldırım Mehmet Nur (MehmetNY) - NOYB + - Huseyin Emre (emreemuzik) - chaironeko - Efe kemal Gürses (efetr1) - Özkan Özeşme (ozkanozsm) @@ -1350,8 +1432,8 @@ Translators: - SuslikV - Mykola Ronik (Mantikor) - Anatoly Belibov (anatoly136ua) - - Sergey (Megadragon) - Vainock + - Ihor Hordiichuk (ihor_ck) - Lino Bico (bicolino34) - Юрій (Devinit) - Gol D. Ace (goldace) @@ -1360,21 +1442,24 @@ Translators: - បងមាន តែអូន (cheaiphone267) - geimfis - L1Q - - Sergii Raboshchuk (Fallenbard) - powerdef + - Sergii Raboshchuk (Fallenbard) - unknowndomain + - lxlalexlxl - Maksym Tymoshyk (maximillian_) - dodgepong Urdu (Pakistan): - Rana Awais (ehtisham) + - Sheikh Ahmed (sheikhahmed) - tahirsada - shamuntohamd - unknowndomain - Gol D. Ace (goldace) Vietnamese: - Johnny “max20091” Utah (boostyourprogram) - - Hưng Nguyễn (hoyostudio) + - Quang Nguyen (quangnguyen.25) - IoeCmcomc (ioecmcomc) + - Hưng Nguyễn (hoyostudio) - ngoisaosang - Dũng Nguyễn (ctctk9) - Drake Strike (phjtieudoc) @@ -1386,7 +1471,7 @@ Translators: - rezarria - unknowndomain - Vũ Hải Tây (tayngungo1999) - - V4Ki3t_VN - - Dawkin Nguyen (dawkinit) - dodgepong + - Dawkin Nguyen (dawkinit) + - V4Ki3t_VN - NCAA diff --git a/CI/before-script-linux.sh b/CI/before-script-linux.sh index 2118a27..5279c93 100755 --- a/CI/before-script-linux.sh +++ b/CI/before-script-linux.sh @@ -3,4 +3,4 @@ set -ex ccache -s || echo "CCache is not available." mkdir build && cd build -cmake -DBUILD_CAPTIONS=ON -DBUILD_BROWSER=ON -DCEF_ROOT_DIR="../cef_binary_${CEF_BUILD_VERSION}_linux64" .. +cmake -DBUILD_BROWSER=ON -DCEF_ROOT_DIR="../cef_binary_${CEF_BUILD_VERSION}_linux64" .. diff --git a/CI/before-script-osx.sh b/CI/before-script-osx.sh index 3e37b17..fb7b213 100755 --- a/CI/before-script-osx.sh +++ b/CI/before-script-osx.sh @@ -13,6 +13,5 @@ cmake -DENABLE_SPARKLE_UPDATER=ON \ -DVLCPath=$PWD/../../vlc-3.0.8 \ -DBUILD_BROWSER=ON \ -DBROWSER_DEPLOY=ON \ --DBUILD_CAPTIONS=ON \ -DWITH_RTMPS=ON \ -DCEF_ROOT_DIR=$PWD/../../cef_binary_${CEF_BUILD_VERSION}_macosx64 .. diff --git a/CI/full-build-macos.sh b/CI/full-build-macos.sh index 5772bfe..1f3d684 100755 --- a/CI/full-build-macos.sh +++ b/CI/full-build-macos.sh @@ -38,6 +38,7 @@ PRODUCT_NAME="OBS-Studio" CHECKOUT_DIR="$(git rev-parse --show-toplevel)" DEPS_BUILD_DIR="${CHECKOUT_DIR}/../obs-build-dependencies" BUILD_DIR="${BUILD_DIR:-build}" +BUILD_CONFIG=${BUILD_CONFIG:-RelWithDebInfo} CI_SCRIPTS="${CHECKOUT_DIR}/CI/scripts/macos" CI_WORKFLOW="${CHECKOUT_DIR}/.github/workflows/main.yml" CI_CEF_VERSION=$(cat ${CI_WORKFLOW} | sed -En "s/[ ]+CEF_BUILD_VERSION: '([0-9]+)'/\1/p") @@ -45,6 +46,7 @@ CI_DEPS_VERSION=$(cat ${CI_WORKFLOW} | sed -En "s/[ ]+MACOS_DEPS_VERSION: '([0-9 CI_VLC_VERSION=$(cat ${CI_WORKFLOW} | sed -En "s/[ ]+VLC_VERSION: '([0-9\.]+)'/\1/p") CI_SPARKLE_VERSION=$(cat ${CI_WORKFLOW} | sed -En "s/[ ]+SPARKLE_VERSION: '([0-9\.]+)'/\1/p") CI_QT_VERSION=$(cat ${CI_WORKFLOW} | sed -En "s/[ ]+QT_VERSION: '([0-9\.]+)'/\1/p" | head -1) +CI_MIN_MACOS_VERSION=$(cat ${CI_WORKFLOW} | sed -En "s/[ ]+MIN_MACOS_VERSION: '([0-9\.]+)'/\1/p") BUILD_DEPS=( "obs-deps ${MACOS_DEPS_VERSION:-${CI_DEPS_VERSION}}" @@ -113,13 +115,32 @@ caught_error() { } ## CHECK AND INSTALL DEPENDENCIES ## +check_macos_version() { + MIN_VERSION=${MIN_MACOS_VERSION:-${CI_MIN_MACOS_VERSION}} + MIN_MAJOR=$(echo ${MIN_VERSION} | cut -d '.' -f 1) + MIN_MINOR=$(echo ${MIN_VERSION} | cut -d '.' -f 2) + + if [ "${MACOS_MAJOR}" -lt "11" ] && [ "${MACOS_MINOR}" -lt "${MIN_MINOR}" ]; then + error "WARNING: Minimum required macOS version is ${MIN_VERSION}, but running on ${MACOS_VERSION}" + fi +} + install_homebrew_deps() { if ! exists brew; then error "Homebrew not found - please install homebrew (https://brew.sh)" exit 1 fi - brew update + if [ -d /usr/local/opt/openssl@1.0.2t ]; then + brew uninstall openssl@1.0.2t + brew untap local/openssl + fi + + if [ -d /usr/local/opt/python@2.7.17 ]; then + brew uninstall python@2.7.17 + brew untap local/python2 + fi + brew bundle --file ${CI_SCRIPTS}/Brewfile check_curl @@ -195,16 +216,14 @@ install_cef() { tar -xf ./cef_binary_${1}_macosx64.tar.bz2 cd ./cef_binary_${1}_macosx64 step "Fix tests..." - # remove a broken test sed -i '.orig' '/add_subdirectory(tests\/ceftests)/d' ./CMakeLists.txt - # target 10.11 - sed -i '.orig' s/\"10.9\"/\"10.11\"/ ./cmake/cef_variables.cmake + sed -i '.orig' s/\"10.9\"/\"${MIN_MACOS_VERSION:-${CI_MIN_MACOS_VERSION}}\"/ ./cmake/cef_variables.cmake ensure_dir ./build step "Run CMAKE..." cmake \ - -DCMAKE_CXX_FLAGS="-std=c++11 -stdlib=libc++"\ + -DCMAKE_CXX_FLAGS="-std=c++11 -stdlib=libc++ -Wno-deprecated-declarations"\ -DCMAKE_EXE_LINKER_FLAGS="-std=c++11 -stdlib=libc++"\ - -DCMAKE_OSX_DEPLOYMENT_TARGET=10.11 \ + -DCMAKE_OSX_DEPLOYMENT_TARGET=${MIN_MACOS_VERSION:-${CI_MIN_MACOS_VERSION}} \ .. step "Build..." make -j4 @@ -251,7 +270,7 @@ configure_obs_build() { hr "Run CMAKE for OBS..." cmake -DENABLE_SPARKLE_UPDATER=ON \ - -DCMAKE_OSX_DEPLOYMENT_TARGET=10.13 \ + -DCMAKE_OSX_DEPLOYMENT_TARGET=${MIN_MACOS_VERSION:-${CI_MIN_MACOS_VERSION}} \ -DDISABLE_PYTHON=ON \ -DQTDIR="/tmp/obsdeps" \ -DSWIGDIR="/tmp/obsdeps" \ @@ -259,9 +278,9 @@ configure_obs_build() { -DVLCPath="${DEPS_BUILD_DIR}/vlc-${VLC_VERSION:-${CI_VLC_VERSION}}" \ -DBUILD_BROWSER=ON \ -DBROWSER_DEPLOY=ON \ - -DBUILD_CAPTIONS=ON \ -DWITH_RTMPS=ON \ -DCEF_ROOT_DIR="${DEPS_BUILD_DIR}/cef_binary_${CEF_BUILD_VERSION:-${CI_CEF_VERSION}}_macosx64" \ + -DCMAKE_BUILD_TYPE="${BUILD_CONFIG}" \ .. } @@ -287,9 +306,10 @@ bundle_dylibs() { ${CI_SCRIPTS}/app/dylibbundler -cd -of -a ./OBS.app -q -f \ -s ./OBS.app/Contents/MacOS \ -s "${DEPS_BUILD_DIR}/sparkle/Sparkle.framework" \ - -s ./rundir/RelWithDebInfo/bin/ \ + -s ./rundir/${BUILD_CONFIG}/bin/ \ -x ./OBS.app/Contents/PlugIns/coreaudio-encoder.so \ -x ./OBS.app/Contents/PlugIns/decklink-ouput-ui.so \ + -x ./OBS.app/Contents/PlugIns/decklink-captions.so \ -x ./OBS.app/Contents/PlugIns/frontend-tools.so \ -x ./OBS.app/Contents/PlugIns/image-source.so \ -x ./OBS.app/Contents/PlugIns/linux-jack.so \ @@ -298,6 +318,7 @@ bundle_dylibs() { -x ./OBS.app/Contents/PlugIns/mac-decklink.so \ -x ./OBS.app/Contents/PlugIns/mac-syphon.so \ -x ./OBS.app/Contents/PlugIns/mac-vth264.so \ + -x ./OBS.app/Contents/PlugIns/mac-virtualcam.so \ -x ./OBS.app/Contents/PlugIns/obs-browser.so \ -x ./OBS.app/Contents/PlugIns/obs-browser-page \ -x ./OBS.app/Contents/PlugIns/obs-ffmpeg.so \ @@ -312,7 +333,12 @@ bundle_dylibs() { -x ./OBS.app/Contents/PlugIns/obs-libfdk.so \ -x ./OBS.app/Contents/PlugIns/obs-outputs.so step "Move libobs-opengl to final destination" - cp ./libobs-opengl/libobs-opengl.so ./OBS.app/Contents/Frameworks + + if [ -f "./libobs-opengl/libobs-opengl.so" ]; then + cp ./libobs-opengl/libobs-opengl.so ./OBS.app/Contents/Frameworks + else + cp ./libobs-opengl/${BUILD_CONFIG}/libobs-opengl.so ./OBS.app/Contents/Frameworks + fi step "Copy QtNetwork for plugin support" cp -R /tmp/obsdeps/lib/QtNetwork.framework ./OBS.app/Contents/Frameworks @@ -334,14 +360,14 @@ install_frameworks() { hr "Adding Chromium Embedded Framework" step "Copy Framework..." - sudo cp -R "${DEPS_BUILD_DIR}/cef_binary_${CEF_BUILD_VERSION:-${CI_CEF_VERSION}}_macosx64/Release/Chromium Embedded Framework.framework" ./OBS.app/Contents/Frameworks/ - sudo chown -R $(whoami) ./OBS.app/Contents/Frameworks/ + cp -R "${DEPS_BUILD_DIR}/cef_binary_${CEF_BUILD_VERSION:-${CI_CEF_VERSION}}_macosx64/Release/Chromium Embedded Framework.framework" ./OBS.app/Contents/Frameworks/ + chown -R $(whoami) ./OBS.app/Contents/Frameworks/ } prepare_macos_bundle() { ensure_dir "${CHECKOUT_DIR}/${BUILD_DIR}" - if [ ! -d ./rundir/RelWithDebInfo/bin ]; then + if [ ! -d ./rundir/${BUILD_CONFIG}/bin ]; then error "No OBS build found" return fi @@ -354,12 +380,12 @@ prepare_macos_bundle() { mkdir OBS.app/Contents/PlugIns mkdir OBS.app/Contents/Resources - cp rundir/RelWithDebInfo/bin/obs ./OBS.app/Contents/MacOS - cp rundir/RelWithDebInfo/bin/obs-ffmpeg-mux ./OBS.app/Contents/MacOS - cp rundir/RelWithDebInfo/bin/libobsglad.0.dylib ./OBS.app/Contents/MacOS - cp -R rundir/RelWithDebInfo/data ./OBS.app/Contents/Resources - cp ${CI_SCRIPTS}/app/obs.icns ./OBS.app/Contents/Resources - cp -R rundir/RelWithDebInfo/obs-plugins/ ./OBS.app/Contents/PlugIns + cp rundir/${BUILD_CONFIG}/bin/obs ./OBS.app/Contents/MacOS + cp rundir/${BUILD_CONFIG}/bin/obs-ffmpeg-mux ./OBS.app/Contents/MacOS + cp rundir/${BUILD_CONFIG}/bin/libobsglad.0.dylib ./OBS.app/Contents/MacOS + cp -R rundir/${BUILD_CONFIG}/data ./OBS.app/Contents/Resources + cp ${CI_SCRIPTS}/app/AppIcon.icns ./OBS.app/Contents/Resources + cp -R rundir/${BUILD_CONFIG}/obs-plugins/ ./OBS.app/Contents/PlugIns cp ${CI_SCRIPTS}/app/Info.plist ./OBS.app/Contents # Scripting plugins are required to be placed in same directory as binary if [ -d ./OBS.app/Contents/Resources/data/obs-scripting ]; then @@ -483,6 +509,11 @@ codesign_bundle() { codesign --force --options runtime --sign "${CODESIGN_IDENT}" --deep "./OBS.app/Contents/Frameworks/Chromium Embedded Framework.framework" echo -n "${COLOR_RESET}" + step "Code-sign DAL Plugin..." + echo -n "${COLOR_ORANGE}" + codesign --force --options runtime --deep --sign "${CODESIGN_IDENT}" "./OBS.app/Contents/Resources/data/obs-mac-virtualcam.plugin" + echo -n "${COLOR_RESET}" + step "Code-sign OBS code..." echo -n "${COLOR_ORANGE}" codesign --force --options runtime --entitlements "${CI_SCRIPTS}/app/entitlements.plist" --sign "${CODESIGN_IDENT}" --deep ./OBS.app @@ -603,6 +634,7 @@ print_usage() { obs-build-main() { ensure_dir ${CHECKOUT_DIR} + check_macos_version step "Fetching OBS tags..." git fetch origin --tags GIT_BRANCH=$(git rev-parse --abbrev-ref HEAD) @@ -647,4 +679,4 @@ obs-build-main() { cleanup } -obs-build-main $* \ No newline at end of file +obs-build-main $* diff --git a/CI/install-dependencies-linux.sh b/CI/install-dependencies-linux.sh index 0d92fbf..dd6bb61 100755 --- a/CI/install-dependencies-linux.sh +++ b/CI/install-dependencies-linux.sh @@ -43,7 +43,9 @@ sudo apt-get install -y \ python3-dev \ qtbase5-dev \ libqt5svg5-dev \ - swig + swig \ + linux-generic \ + v4l2loopback-dkms # build cef wget --quiet --retry-connrefused --waitretry=1 https://cdn-fastly.obsproject.com/downloads/cef_binary_${CEF_BUILD_VERSION}_linux64.tar.bz2 diff --git a/CI/install-script-win.cmd b/CI/install-script-win.cmd index ff0641a..c12773d 100644 --- a/CI/install-script-win.cmd +++ b/CI/install-script-win.cmd @@ -14,16 +14,17 @@ set QTDIR64=C:\QtDep\5.10.1\msvc2017_64 set CEF_32=%CD%\CEF_32\cef_binary_%CEF_VERSION%_windows32_minimal set CEF_64=%CD%\CEF_64\cef_binary_%CEF_VERSION%_windows64_minimal set build_config=RelWithDebInfo +set VIRTUALCAM-GUID=A3FCE0F5-3493-419F-958A-ABA1250EC20B mkdir build build32 build64 if "%TWITCH-CLIENTID%"=="$(twitch_clientid)" ( cd ./build32 -cmake -G "Visual Studio 16 2019" -A Win32 -DCMAKE_SYSTEM_VERSION=10.0 -DCOPIED_DEPENDENCIES=false -DCOPY_DEPENDENCIES=true -DENABLE_VLC=ON -DBUILD_CAPTIONS=true -DCOMPILE_D3D12_HOOK=true -DBUILD_BROWSER=true -DCEF_ROOT_DIR=%CEF_32% .. +cmake -G "Visual Studio 16 2019" -A Win32 -DCMAKE_SYSTEM_VERSION=10.0 -DCOPIED_DEPENDENCIES=false -DCOPY_DEPENDENCIES=true -DENABLE_VLC=ON -DCOMPILE_D3D12_HOOK=true -DBUILD_BROWSER=true -DCEF_ROOT_DIR=%CEF_32% -DVIRTUALCAM_GUID="%VIRTUALCAM-GUID%" .. cd ../build64 -cmake -G "Visual Studio 16 2019" -A x64 -DCMAKE_SYSTEM_VERSION=10.0 -DCOPIED_DEPENDENCIES=false -DCOPY_DEPENDENCIES=true -DENABLE_VLC=ON -DBUILD_CAPTIONS=true -DCOMPILE_D3D12_HOOK=true -DBUILD_BROWSER=true -DCEF_ROOT_DIR=%CEF_64% .. +cmake -G "Visual Studio 16 2019" -A x64 -DCMAKE_SYSTEM_VERSION=10.0 -DCOPIED_DEPENDENCIES=false -DCOPY_DEPENDENCIES=true -DENABLE_VLC=ON -DCOMPILE_D3D12_HOOK=true -DBUILD_BROWSER=true -DCEF_ROOT_DIR=%CEF_64% -DVIRTUALCAM_GUID="%VIRTUALCAM-GUID%" .. ) else ( cd ./build32 -cmake -G "Visual Studio 16 2019" -A Win32 -DCMAKE_SYSTEM_VERSION=10.0 -DCOPIED_DEPENDENCIES=false -DCOPY_DEPENDENCIES=true -DENABLE_VLC=ON -DBUILD_CAPTIONS=true -DCOMPILE_D3D12_HOOK=true -DBUILD_BROWSER=true -DCEF_ROOT_DIR=%CEF_32% -DTWITCH_CLIENTID="%TWITCH-CLIENTID%" -DTWITCH_HASH="%TWITCH-HASH%" -DRESTREAM_CLIENTID="%RESTREAM-CLIENTID%" -DRESTREAM_HASH="%RESTREAM-HASH%" .. +cmake -G "Visual Studio 16 2019" -A Win32 -DCMAKE_SYSTEM_VERSION=10.0 -DCOPIED_DEPENDENCIES=false -DCOPY_DEPENDENCIES=true -DENABLE_VLC=ON -DCOMPILE_D3D12_HOOK=true -DBUILD_BROWSER=true -DCEF_ROOT_DIR=%CEF_32% -DTWITCH_CLIENTID="%TWITCH-CLIENTID%" -DTWITCH_HASH="%TWITCH-HASH%" -DRESTREAM_CLIENTID="%RESTREAM-CLIENTID%" -DRESTREAM_HASH="%RESTREAM-HASH%" -DVIRTUALCAM_GUID="%VIRTUALCAM-GUID%" .. cd ../build64 -cmake -G "Visual Studio 16 2019" -A x64 -DCMAKE_SYSTEM_VERSION=10.0 -DCOPIED_DEPENDENCIES=false -DCOPY_DEPENDENCIES=true -DENABLE_VLC=ON -DBUILD_CAPTIONS=true -DCOMPILE_D3D12_HOOK=true -DBUILD_BROWSER=true -DCEF_ROOT_DIR=%CEF_64% -DTWITCH_CLIENTID="%TWITCH-CLIENTID%" -DTWITCH_HASH="%TWITCH-HASH%" -DRESTREAM_CLIENTID="%RESTREAM-CLIENTID%" -DRESTREAM_HASH="%RESTREAM-HASH%" .. +cmake -G "Visual Studio 16 2019" -A x64 -DCMAKE_SYSTEM_VERSION=10.0 -DCOPIED_DEPENDENCIES=false -DCOPY_DEPENDENCIES=true -DENABLE_VLC=ON -DCOMPILE_D3D12_HOOK=true -DBUILD_BROWSER=true -DCEF_ROOT_DIR=%CEF_64% -DTWITCH_CLIENTID="%TWITCH-CLIENTID%" -DTWITCH_HASH="%TWITCH-HASH%" -DRESTREAM_CLIENTID="%RESTREAM-CLIENTID%" -DRESTREAM_HASH="%RESTREAM-HASH%" -DVIRTUALCAM_GUID="%VIRTUALCAM-GUID%" .. ) cd .. diff --git a/CI/scripts/macos/package/settings.json.template b/CI/scripts/macos/package/settings.json.template index 4bcc076..de39e03 100644 --- a/CI/scripts/macos/package/settings.json.template +++ b/CI/scripts/macos/package/settings.json.template @@ -1,7 +1,7 @@ { "title": "OBS-Studio $$VERSION$$", "background": "$$CI_PATH$$/package/background.tiff", - "icon": "$$CI_PATH$$/app/obs.icns", + "icon": "$$CI_PATH$$/app/AppIcon.icns", "format": "ULFO", "icon-size": 96, "window": { diff --git a/CI/scripts/macos/packageApp.sh b/CI/scripts/macos/packageApp.sh deleted file mode 100755 index eb5e20e..0000000 --- a/CI/scripts/macos/packageApp.sh +++ /dev/null @@ -1,78 +0,0 @@ -#!/usr/bin/env bash - -# Exit if something fails -set -e - -rm -rf ./OBS.app - -mkdir OBS.app -mkdir OBS.app/Contents -mkdir OBS.app/Contents/MacOS -mkdir OBS.app/Contents/PlugIns -mkdir OBS.app/Contents/Resources - -cp -R rundir/RelWithDebInfo/bin/ ./OBS.app/Contents/MacOS -cp -R rundir/RelWithDebInfo/data ./OBS.app/Contents/Resources -cp ../CI/scripts/macos/app/obs.icns ./OBS.app/Contents/Resources -cp -R rundir/RelWithDebInfo/obs-plugins/ ./OBS.app/Contents/PlugIns -cp ../CI/scripts/macos/app/Info.plist ./OBS.app/Contents - -../CI/scripts/macos/package/dylibBundler -b -cd -d ./OBS.app/Contents/Frameworks -p @executable_path/../Frameworks/ \ --s ./OBS.app/Contents/MacOS \ --x ./OBS.app/Contents/PlugIns/coreaudio-encoder.so \ --x ./OBS.app/Contents/PlugIns/decklink-ouput-ui.so \ --x ./OBS.app/Contents/PlugIns/frontend-tools.so \ --x ./OBS.app/Contents/PlugIns/image-source.so \ --x ./OBS.app/Contents/PlugIns/linux-jack.so \ --x ./OBS.app/Contents/PlugIns/mac-avcapture.so \ --x ./OBS.app/Contents/PlugIns/mac-capture.so \ --x ./OBS.app/Contents/PlugIns/mac-decklink.so \ --x ./OBS.app/Contents/PlugIns/mac-syphon.so \ --x ./OBS.app/Contents/PlugIns/mac-vth264.so \ --x ./OBS.app/Contents/PlugIns/obs-browser.so \ --x ./OBS.app/Contents/PlugIns/obs-browser-page \ --x ./OBS.app/Contents/PlugIns/obs-ffmpeg.so \ --x ./OBS.app/Contents/PlugIns/obs-filters.so \ --x ./OBS.app/Contents/PlugIns/obs-transitions.so \ --x ./OBS.app/Contents/PlugIns/obs-vst.so \ --x ./OBS.app/Contents/PlugIns/rtmp-services.so \ --x ./OBS.app/Contents/MacOS/obs \ --x ./OBS.app/Contents/MacOS/obs-ffmpeg-mux \ --x ./OBS.app/Contents/MacOS/obslua.so \ --x ./OBS.app/Contents/PlugIns/obs-x264.so \ --x ./OBS.app/Contents/PlugIns/text-freetype2.so \ --x ./OBS.app/Contents/PlugIns/obs-libfdk.so -# -x ./OBS.app/Contents/MacOS/_obspython.so \ -# -x ./OBS.app/Contents/PlugIns/obs-outputs.so \ - -/usr/local/Cellar/qt/${QT_VERSION}/bin/macdeployqt ./OBS.app - -mv ./OBS.app/Contents/MacOS/libobs-opengl.so ./OBS.app/Contents/Frameworks - -rm -f -r ./OBS.app/Contents/Frameworks/QtNetwork.framework - -# put qt network in here becasuse streamdeck uses it -cp -R /usr/local/opt/qt/lib/QtNetwork.framework ./OBS.app/Contents/Frameworks -chmod -R +w ./OBS.app/Contents/Frameworks/QtNetwork.framework -rm -r ./OBS.app/Contents/Frameworks/QtNetwork.framework/Headers -rm -r ./OBS.app/Contents/Frameworks/QtNetwork.framework/Versions/5/Headers/ -chmod 644 ./OBS.app/Contents/Frameworks/QtNetwork.framework/Versions/5/Resources/Info.plist -install_name_tool -id @executable_path/../Frameworks/QtNetwork.framework/Versions/5/QtNetwork ./OBS.app/Contents/Frameworks/QtNetwork.framework/Versions/5/QtNetwork -install_name_tool -change /usr/local/Cellar/qt/${QT_VERSION}/lib/QtCore.framework/Versions/5/QtCore @executable_path/../Frameworks/QtCore.framework/Versions/5/QtCore ./OBS.app/Contents/Frameworks/QtNetwork.framework/Versions/5/QtNetwork - - -# decklink ui qt -install_name_tool -change /usr/local/opt/qt/lib/QtGui.framework/Versions/5/QtGui @executable_path/../Frameworks/QtGui.framework/Versions/5/QtGui ./OBS.app/Contents/PlugIns/decklink-ouput-ui.so -install_name_tool -change /usr/local/opt/qt/lib/QtCore.framework/Versions/5/QtCore @executable_path/../Frameworks/QtCore.framework/Versions/5/QtCore ./OBS.app/Contents/PlugIns/decklink-ouput-ui.so -install_name_tool -change /usr/local/opt/qt/lib/QtWidgets.framework/Versions/5/QtWidgets @executable_path/../Frameworks/QtWidgets.framework/Versions/5/QtWidgets ./OBS.app/Contents/PlugIns/decklink-ouput-ui.so - -# frontend tools qt -install_name_tool -change /usr/local/opt/qt/lib/QtGui.framework/Versions/5/QtGui @executable_path/../Frameworks/QtGui.framework/Versions/5/QtGui ./OBS.app/Contents/PlugIns/frontend-tools.so -install_name_tool -change /usr/local/opt/qt/lib/QtCore.framework/Versions/5/QtCore @executable_path/../Frameworks/QtCore.framework/Versions/5/QtCore ./OBS.app/Contents/PlugIns/frontend-tools.so -install_name_tool -change /usr/local/opt/qt/lib/QtWidgets.framework/Versions/5/QtWidgets @executable_path/../Frameworks/QtWidgets.framework/Versions/5/QtWidgets ./OBS.app/Contents/PlugIns/frontend-tools.so - -# vst qt -install_name_tool -change /usr/local/opt/qt/lib/QtGui.framework/Versions/5/QtGui @executable_path/../Frameworks/QtGui.framework/Versions/5/QtGui ./OBS.app/Contents/PlugIns/obs-vst.so -install_name_tool -change /usr/local/opt/qt/lib/QtCore.framework/Versions/5/QtCore @executable_path/../Frameworks/QtCore.framework/Versions/5/QtCore ./OBS.app/Contents/PlugIns/obs-vst.so -install_name_tool -change /usr/local/opt/qt/lib/QtWidgets.framework/Versions/5/QtWidgets @executable_path/../Frameworks/QtWidgets.framework/Versions/5/QtWidgets ./OBS.app/Contents/PlugIns/obs-vst.so -install_name_tool -change /usr/local/opt/qt/lib/QtMacExtras.framework/Versions/5/QtMacExtras @executable_path/../Frameworks/QtMacExtras.framework/Versions/5/QtMacExtras ./OBS.app/Contents/PlugIns/obs-vst.so diff --git a/CI/scripts/macos/prepareApp.sh b/CI/scripts/macos/prepareApp.sh deleted file mode 100755 index 1a6de88..0000000 --- a/CI/scripts/macos/prepareApp.sh +++ /dev/null @@ -1,41 +0,0 @@ -#!/usr/bin/env bash - -# Exit if something fails -set -e - -cd ./build - -mv ./rundir/RelWithDebInfo/data/obs-scripting/obslua.so ./rundir/RelWithDebInfo/bin/ -mv ./rundir/RelWithDebInfo/data/obs-scripting/_obspython.so ./rundir/RelWithDebInfo/bin/ -mv ./rundir/RelWithDebInfo/data/obs-scripting/obspython.py ./rundir/RelWithDebInfo/bin/ - -../CI/scripts/macos/packageApp.sh - -# fix obs outputs plugin it doesn't play nicely with dylibBundler at the moment -chmod +w ./OBS.app/Contents/Frameworks/*.dylib -install_name_tool -change libmbedtls.12.dylib @executable_path/../Frameworks/libmbedtls.12.dylib ./OBS.app/Contents/Plugins/obs-outputs.so -install_name_tool -change libmbedcrypto.3.dylib @executable_path/../Frameworks/libmbedcrypto.3.dylib ./OBS.app/Contents/Plugins/obs-outputs.so -install_name_tool -change libmbedx509.0.dylib @executable_path/../Frameworks/libmbedx509.0.dylib ./OBS.app/Contents/Plugins/obs-outputs.so -install_name_tool -change /usr/local/opt/curl/lib/libcurl.4.dylib @executable_path/../Frameworks/libcurl.4.dylib ./OBS.app/Contents/Plugins/obs-outputs.so -install_name_tool -change @rpath/libobs.0.dylib @executable_path/../Frameworks/libobs.0.dylib ./OBS.app/Contents/Plugins/obs-outputs.so -install_name_tool -change /tmp/obsdeps/bin/libjansson.4.dylib @executable_path/../Frameworks/libjansson.4.dylib ./OBS.app/Contents/Plugins/obs-outputs.so - -cp -R ${GITHUB_WORKSPACE}/cmbuild/sparkle/Sparkle.framework ./OBS.app/Contents/Frameworks/ -install_name_tool -change @rpath/Sparkle.framework/Versions/A/Sparkle @executable_path/../Frameworks/Sparkle.framework/Versions/A/Sparkle ./OBS.app/Contents/MacOS/obs - -sudo mkdir -p ./OBS.app/Contents/Frameworks -sudo cp -R ${GITHUB_WORKSPACE}/cmbuild/cef_binary_${CEF_BUILD_VERSION}_macosx64/Release/Chromium\ Embedded\ Framework.framework ./OBS.app/Contents/Frameworks/ -install_name_tool -change /usr/local/opt/qt/lib/QtGui.framework/Versions/5/QtGui @executable_path/../Frameworks/QtGui.framework/Versions/5/QtGui ./OBS.app/Contents/Plugins/obs-browser.so -install_name_tool -change /usr/local/opt/qt/lib/QtCore.framework/Versions/5/QtCore @executable_path/../Frameworks/QtCore.framework/Versions/5/QtCore ./OBS.app/Contents/Plugins/obs-browser.so -install_name_tool -change /usr/local/opt/qt/lib/QtWidgets.framework/Versions/5/QtWidgets @executable_path/../Frameworks/QtWidgets.framework/Versions/5/QtWidgets ./OBS.app/Contents/Plugins/obs-browser.so - -cp ../CI/scripts/macos/app/OBSPublicDSAKey.pem ./OBS.app/Contents/Resources - -plutil -insert CFBundleVersion -string $(basename ${GITHUB_REF}) ./OBS.app/Contents/Info.plist -plutil -insert CFBundleShortVersionString -string $(basename ${GITHUB_REF}) ./OBS.app/Contents/Info.plist -plutil -insert OBSFeedsURL -string https://obsproject.com/osx_update/feeds.xml ./OBS.app/Contents/Info.plist -plutil -insert SUFeedURL -string https://obsproject.com/osx_update/stable/updates.xml ./OBS.app/Contents/Info.plist -plutil -insert SUPublicDSAKeyFile -string OBSPublicDSAKey.pem ./OBS.app/Contents/Info.plist - -mv ./OBS.app ../OBS.app -cd - diff --git a/CMakeLists.txt b/CMakeLists.txt index 5bdfe21..8b36df8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,7 +7,7 @@ endif() project(obs-studio) -option(BUILD_CAPTIONS "Build captions" FALSE) +option(DEBUG_FFMPEG_MUX "Debug FFmpeg muxer subprocess" FALSE) set_property(GLOBAL PROPERTY USE_FOLDERS ON) diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index 43c1934..cb1951f 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -5,10 +5,10 @@ Quick Links for Contributing ---------------------------- - Compiling and building OBS Studio: - https://github.com/jp9000/obs-studio/wiki/Install-Instructions + https://github.com/obsproject/obs-studio/wiki/Install-Instructions - - Our bug tracker (linked to forum accounts): - https://obsproject.com/mantis/ + - Our bug tracker: + https://github.com/obsproject/obs-studio/issues - Discord Server: https://obsproject.com/discord diff --git a/UI/CMakeLists.txt b/UI/CMakeLists.txt index df4d264..ae881a3 100644 --- a/UI/CMakeLists.txt +++ b/UI/CMakeLists.txt @@ -81,7 +81,6 @@ include_directories(${LIBCURL_INCLUDE_DIRS}) add_definitions(${LIBCURL_DEFINITIONS}) if(WIN32) - include_directories(${OBS_JANSSON_INCLUDE_DIRS}) include_directories(${BLAKE2_INCLUDE_DIR}) set(obs_PLATFORM_SOURCES @@ -96,8 +95,7 @@ if(WIN32) win-update/win-update-helpers.hpp) set(obs_PLATFORM_LIBRARIES crypt32 - blake2 - ${OBS_JANSSON_IMPORT}) + blake2) if(CMAKE_SIZEOF_VOID_P EQUAL 4) set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /LARGEADDRESSAWARE") @@ -132,6 +130,11 @@ elseif(UNIX) set(obs_PLATFORM_LIBRARIES Qt5::X11Extras) + + if("${CMAKE_SYSTEM_NAME}" MATCHES "FreeBSD") + list(APPEND obs_PLATFORM_LIBRARIES + procstat) + endif() endif() if(BROWSER_AVAILABLE_INTERNAL) @@ -345,7 +348,6 @@ set(obs_UI forms/source-toolbar/color-source-toolbar.ui forms/source-toolbar/text-source-toolbar.ui forms/source-toolbar/media-controls.ui - forms/NameDialog.ui forms/AutoConfigStartPage.ui forms/AutoConfigVideoPage.ui forms/AutoConfigStreamPage.ui diff --git a/UI/adv-audio-control.cpp b/UI/adv-audio-control.cpp index e2d2811..862d746 100644 --- a/UI/adv-audio-control.cpp +++ b/UI/adv-audio-control.cpp @@ -22,7 +22,7 @@ OBSAdvAudioCtrl::OBSAdvAudioCtrl(QGridLayout *, obs_source_t *source_) { QHBoxLayout *hlayout; signal_handler_t *handler = obs_source_get_signal_handler(source); - const char *sourceName = obs_source_get_name(source); + QString sourceName = QT_UTF8(obs_source_get_name(source)); float vol = obs_source_get_volume(source); uint32_t flags = obs_source_get_flags(source); uint32_t mixers = obs_source_get_audio_mixers(source); @@ -90,7 +90,7 @@ OBSAdvAudioCtrl::OBSAdvAudioCtrl(QGridLayout *, obs_source_t *source_) iconLabel->setFixedSize(16, 16); iconLabel->setStyleSheet("background: none"); - nameLabel->setText(QT_UTF8(sourceName)); + nameLabel->setText(sourceName); nameLabel->setAlignment(Qt::AlignVCenter); bool isActive = obs_source_active(source); @@ -100,7 +100,7 @@ OBSAdvAudioCtrl::OBSAdvAudioCtrl(QGridLayout *, obs_source_t *source_) setThemeID(active, "error"); activeContainer->layout()->addWidget(active); activeContainer->layout()->setAlignment(active, Qt::AlignVCenter); - activeContainer->setFixedWidth(50); + activeContainer->setFixedWidth(120); volume->setMinimum(MIN_DB - 0.1); volume->setMaximum(MAX_DB); @@ -109,15 +109,21 @@ OBSAdvAudioCtrl::OBSAdvAudioCtrl(QGridLayout *, obs_source_t *source_) volume->setSuffix(" dB"); volume->setValue(obs_mul_to_db(vol)); volume->setFixedWidth(100); + volume->setAccessibleName( + QTStr("Basic.AdvAudio.VolumeSource").arg(sourceName)); - if (volume->value() < MIN_DB) + if (volume->value() < MIN_DB) { volume->setSpecialValueText("-inf dB"); + volume->setAccessibleDescription("-inf dB"); + } percent->setMinimum(0); percent->setMaximum(2000); percent->setSuffix("%"); percent->setValue((int)(obs_source_get_volume(source) * 100.0f)); percent->setFixedWidth(100); + percent->setAccessibleName( + QTStr("Basic.AdvAudio.VolumeSource").arg(sourceName)); stackedWidget->addWidget(volume); stackedWidget->addWidget(percent); @@ -128,6 +134,8 @@ OBSAdvAudioCtrl::OBSAdvAudioCtrl(QGridLayout *, obs_source_t *source_) SetVolumeWidget(volType); forceMono->setChecked((flags & OBS_SOURCE_FLAG_FORCE_MONO) != 0); + forceMono->setAccessibleName( + QTStr("Basic.AdvAudio.MonoSource").arg(sourceName)); forceMonoContainer->layout()->addWidget(forceMono); forceMonoContainer->layout()->setAlignment(forceMono, Qt::AlignVCenter); @@ -138,6 +146,8 @@ OBSAdvAudioCtrl::OBSAdvAudioCtrl(QGridLayout *, obs_source_t *source_) balance->setMaximum(100); balance->setTickPosition(QSlider::TicksAbove); balance->setTickInterval(50); + balance->setAccessibleName( + QTStr("Basic.AdvAudio.BalanceSource").arg(sourceName)); const char *speakers = config_get_string(main->Config(), "Audio", "ChannelSetup"); @@ -156,6 +166,8 @@ OBSAdvAudioCtrl::OBSAdvAudioCtrl(QGridLayout *, obs_source_t *source_) syncOffset->setSuffix(" ms"); syncOffset->setValue(int(cur_sync / NSEC_PER_MSEC)); syncOffset->setFixedWidth(100); + syncOffset->setAccessibleName( + QTStr("Basic.AdvAudio.SyncOffsetSource").arg(sourceName)); int idx; #if defined(_WIN32) || defined(__APPLE__) || HAVE_PULSEAUDIO @@ -168,20 +180,34 @@ OBSAdvAudioCtrl::OBSAdvAudioCtrl(QGridLayout *, obs_source_t *source_) int mt = (int)obs_source_get_monitoring_type(source); idx = monitoringType->findData(mt); monitoringType->setCurrentIndex(idx); + monitoringType->setAccessibleName( + QTStr("Basic.AdvAudio.MonitoringSource").arg(sourceName)); #endif mixer1->setText("1"); mixer1->setChecked(mixers & (1 << 0)); + mixer1->setAccessibleName( + QTStr("Basic.Settings.Output.Adv.Audio.Track1")); mixer2->setText("2"); mixer2->setChecked(mixers & (1 << 1)); + mixer2->setAccessibleName( + QTStr("Basic.Settings.Output.Adv.Audio.Track2")); mixer3->setText("3"); mixer3->setChecked(mixers & (1 << 2)); + mixer3->setAccessibleName( + QTStr("Basic.Settings.Output.Adv.Audio.Track3")); mixer4->setText("4"); mixer4->setChecked(mixers & (1 << 3)); + mixer4->setAccessibleName( + QTStr("Basic.Settings.Output.Adv.Audio.Track4")); mixer5->setText("5"); mixer5->setChecked(mixers & (1 << 4)); + mixer5->setAccessibleName( + QTStr("Basic.Settings.Output.Adv.Audio.Track5")); mixer6->setText("6"); mixer6->setChecked(mixers & (1 << 5)); + mixer6->setAccessibleName( + QTStr("Basic.Settings.Output.Adv.Audio.Track6")); speaker_layout sl = obs_source_get_speaker_layout(source); diff --git a/UI/context-bar-controls.cpp b/UI/context-bar-controls.cpp index 26704a4..9dff897 100644 --- a/UI/context-bar-controls.cpp +++ b/UI/context-bar-controls.cpp @@ -96,14 +96,6 @@ static int FillPropertyCombo(QComboBox *c, obs_property_t *p, return cur_idx; } -static void SetComboItemDisabled(QComboBox *c, int idx) -{ - QStandardItemModel *model = - dynamic_cast(c->model()); - QStandardItem *item = model->item(idx); - item->setFlags(Qt::NoItemFlags); -} - void UpdateSourceComboToolbarProperties(QComboBox *combo, OBSSource source, obs_properties_t *props, const char *prop_name, bool is_int) @@ -131,7 +123,7 @@ void UpdateSourceComboToolbarProperties(QComboBox *combo, OBSSource source, cur_idx = 0; } - SetComboItemDisabled(combo, cur_idx); + SetComboItemEnabled(combo, cur_idx, false); } combo->setCurrentIndex(cur_idx); @@ -345,7 +337,7 @@ GameCaptureToolbar::GameCaptureToolbar(QWidget *parent, OBSSource source) ui->window->blockSignals(false); if (cur_idx != -1 && obs_property_list_item_disabled(p, cur_idx)) { - SetComboItemDisabled(ui->window, cur_idx); + SetComboItemEnabled(ui->window, cur_idx, false); } UpdateWindowVisibility(); diff --git a/UI/data/locale.ini b/UI/data/locale.ini index b3684e4..004e634 100644 --- a/UI/data/locale.ini +++ b/UI/data/locale.ini @@ -174,3 +174,9 @@ Name=English (GB) [id-ID] Name=Bahasa Indonesia + +[eo-UY] +Name=Esperanto + +[kab-KAB] +Name=Taglizit diff --git a/UI/data/locale/af-ZA.ini b/UI/data/locale/af-ZA.ini index 7b2247b..b9e2ca7 100644 --- a/UI/data/locale/af-ZA.ini +++ b/UI/data/locale/af-ZA.ini @@ -112,5 +112,6 @@ Top="Bo" + diff --git a/UI/data/locale/ar-SA.ini b/UI/data/locale/ar-SA.ini index 63e26d6..8de9bb4 100644 --- a/UI/data/locale/ar-SA.ini +++ b/UI/data/locale/ar-SA.ini @@ -161,6 +161,7 @@ Basic.AutoConfig.StreamPage.DisconnectAccount="إلغاء ربط الحساب" Basic.AutoConfig.StreamPage.DisconnectAccount.Confirm.Title="إلغاء ربط الحساب؟" Basic.AutoConfig.StreamPage.DisconnectAccount.Confirm.Text="هذا التغيير سيتم تطبيقه مباشرة. هل أنت متأكد من أنك تريد إلغاء ربط حسابك؟" Basic.AutoConfig.StreamPage.GetStreamKey="جلب مفتاح البث" +Basic.AutoConfig.StreamPage.MoreInfo="مزيد من المعلومات" Basic.AutoConfig.StreamPage.UseStreamKey="استخدم مفتاح البث" Basic.AutoConfig.StreamPage.Service="خدمة" Basic.AutoConfig.StreamPage.Service.ShowAll="عرض الكل..." @@ -365,8 +366,6 @@ Deinterlacing.Yadif2x="Yadif 2x" Deinterlacing.TopFieldFirst="أعلى الحقل الأول" Deinterlacing.BottomFieldFirst="أسفل الحقل الأول" -VolControl.SliderUnmuted="حجم شريط التمرير ل '%1': %2" -VolControl.SliderMuted="حجم شريط التمرير ل '%1': %2 (كتم)" VolControl.Mute="كتم الصوت '%1'" VolControl.Properties="خصائص ل '%1'" @@ -382,6 +381,7 @@ Basic.Main.RenameSceneCollection.Title="اعادة تسمية مجموعة مش AddProfile.Title="إضافة ملف تعريف" AddProfile.Text="الرجاء إدخال اسم الملف التعريفي" +AddProfile.WizardCheckbox="معالج التكوين التلقائي" RenameProfile.Title="إعادة تسمية الملف التعريفي" @@ -396,6 +396,9 @@ Basic.SourceSelect.CreateNew="انشاء جديد" Basic.SourceSelect.AddExisting="إضافة عنصر موجود" Basic.SourceSelect.AddVisible="جعل المصدر ظاهراً" +Basic.Main.Sources.Visibility="الرؤية" +Basic.Main.Sources.Lock="قفل" + Basic.PropertiesWindow="خصائص ل '%1'" Basic.PropertiesWindow.AutoSelectFormat="%1 (اختيار تلقائي: %2)" Basic.PropertiesWindow.SelectColor="تحديد اللون" @@ -608,15 +611,26 @@ Basic.Settings.General.AutomaticCollectionSearch="البحث عن المواقع Basic.Settings.General.SwitchOnDoubleClick="الانتقال إلى المشهد عند النقر المزدوج" Basic.Settings.General.StudioPortraitLayout="تمكين التخطيط العامودي/الرأسي" Basic.Settings.General.TogglePreviewProgramLabels="إظهار تسميات المعاينة/البرنامج" +Basic.Settings.General.Multiview="عرض متعدد" +Basic.Settings.General.Multiview.MouseSwitch="انقر للتبديل بين المشاهد" Basic.Settings.General.Multiview.DrawSourceNames="إظهار أسماء المشهد" +Basic.Settings.General.Multiview.DrawSafeAreas="رسم مناطق آمنة (EBU R 95)" Basic.Settings.Stream="بث" Basic.Settings.Stream.StreamType="نوع البث" +Basic.Settings.Stream.Custom.UseAuthentication="استخدام المصادقة" Basic.Settings.Stream.Custom.Username="اسم المستخدم" Basic.Settings.Stream.Custom.Password="كلمة السر" +Basic.Settings.Stream.TTVAddon="Twitch إضافات المحادثة" Basic.Settings.Stream.TTVAddon.None="بدون" Basic.Settings.Stream.MissingSettingAlert="إعداد البث مفقود" Basic.Settings.Stream.StreamSettingsWarning="فتح الإعدادات" +Basic.Settings.Stream.IgnoreRecommended="تجاهل توصيات إعداد خدمات البث" +Basic.Settings.Stream.IgnoreRecommended.Warn.Title="تجاوز الإعدادات الموصى بها" +Basic.Settings.Stream.IgnoreRecommended.Warn.Text="تحذير: تجاهل قيود الخدمة قد يؤدي إلى تدهور جودة البث أو منعك من البث.\n\nالمتابعة؟" +Basic.Settings.Stream.Recommended.MaxVideoBitrate="الحد الأقصى للفيديو: %1 كيلو بايت" +Basic.Settings.Stream.Recommended.MaxAudioBitrate="أقصى معدل للصوت: %1 كيلو بايت" +Basic.Settings.Stream.Recommended.MaxFPS="الحد الأقصى من FPS: %1" Basic.Settings.Output="المخرج" Basic.Settings.Output.Format="صيغة التسجيل" @@ -627,27 +641,37 @@ Basic.Settings.Output.Mode="نوع المخرج" Basic.Settings.Output.Mode.Simple="بسيط" Basic.Settings.Output.Mode.Adv="متقدم" Basic.Settings.Output.Mode.FFmpeg="مخرج FFmpeg" +Basic.Settings.Output.ReplayBuffer.Suffix="اللاحق" Basic.Settings.Output.Simple.SavePath="مسار التسجيل" Basic.Settings.Output.Simple.RecordingQuality="جودة التسجيل" 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، وهو الحد الأعلى لخدمة البث الحالية." Basic.Settings.Output.Simple.Warn.Lossless.Msg="هل أنت متأكد أنك تريد استخدام الجودة الغير فقودة؟" Basic.Settings.Output.Simple.Warn.Lossless.Title="تحذير الجودة الغير فقودة!" 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.TwitchVodTrack="تويتر مسار VOD (استخدم المسار 2)" +Basic.Settings.Output.Warn.EnforceResolutionFPS.Title="دقة / معدل إطار غير متوافق" +Basic.Settings.Output.Warn.EnforceResolutionFPS.Resolution="الدقة: %1" Basic.Settings.Output.VideoBitrate="معدل البت للفيديو" Basic.Settings.Output.AudioBitrate="معدل البت للصوت" Basic.Settings.Output.Reconnect="إعادة الاتصال تلقائياً" Basic.Settings.Output.MaxRetries="أقصى عدد للمحاولات" +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.Audio.Track5="المسار 5" +Basic.Settings.Output.Adv.Audio.Track6="المسار 6" +Basic.Settings.Output.Adv.Recording="جارٍ التسجيل" +Basic.Settings.Output.Adv.Recording.Type="النّوع" Basic.Settings.Output.Adv.Recording.Type.Standard="قياسي" Basic.Settings.Output.Adv.FFmpeg.Type.URL="التصدير إلى رابط URL" Basic.Settings.Output.Adv.FFmpeg.Type.RecordToFile="التصدير إلى ملف" @@ -715,6 +739,8 @@ Basic.Settings.Advanced.Video.ColorRange.Partial="جزئي" Basic.Settings.Advanced.Video.ColorRange.Full="كامل" Basic.AdvAudio.ActiveOnly="المصادر الفعّالة فقط" +Basic.AdvAudio.Name="الاسم" +Basic.AdvAudio.VolumeSource="حجم ل '%1'" diff --git a/UI/data/locale/az-AZ.ini b/UI/data/locale/az-AZ.ini index d1041b8..321820b 100644 --- a/UI/data/locale/az-AZ.ini +++ b/UI/data/locale/az-AZ.ini @@ -37,6 +37,7 @@ SceneWindow="Pəncərəli Projektor (Səhnə)" SourceWindow="Pəncərəli Projektor (Mənbə)" MultiviewProjector="Çoxlu baxış (Tam ekran)" MultiviewWindowed="Çoxlu baxış (Pəncərəli)" +ResizeProjectorWindowToContent="Pəncərəni məzmuna uyğunlaşdır" Clear="Təmizlə" Revert="Geri qaytar" Show="Göstər" @@ -49,6 +50,9 @@ Enable="Fəallaşdır" DisableOSXVSync="macOS V-Sync-i sıradan çıxart" ResetOSXVSyncOnExit="macOS V-Sync-i Çıxışda Sıfırla" HighResourceUsage="Kodlama həddindən artıq yükləndi! Video tənzimləmələrini azaltmağı və ya daha sürətli kodlama ön tənzimini istifadə etməyi düşünün." +Transition="Keçid" +QuickTransitions="Cəld Keçidlər" +FadeToBlack="Qara rəngə solma" Left="Sol" Right="Sa]" Top="Üst" @@ -65,9 +69,12 @@ Copy="Kopyala" Paste="Yapışdır" PasteReference="Yapışdır (İstinad)" PasteDuplicate="Yapışdır (Çoxalt)" +RemuxRecordings="Qeydləri remux et" Next="Növbəti" Back="Geri" Defaults="İlkin" +HideMixer="Mikserdə gizlət" +TransitionOverride="Keçidə əhəmiyyət vermə" None="Heç biri" StudioMode.Preview="Önbaxış" StudioMode.Program="Proqram" @@ -77,13 +84,28 @@ Group="Qrup" DoNotShowAgain="Təkrar göstərmə" Default="(İlkin)" Calculating="Hesablanır..." +Fullscreen="Tam ekran" +Windowed="Pəncərəli" +Percent="Faiz" +RefreshBrowser="Təzələ" +AspectRatio="Əmsal nisbəti %1:%2" +LockVolume="Səs həcmini kilidlə" +LogViewer="Jurnal bax" +ShowOnStartup="Başlanğıcda göstər" OpenFile="Faylı aç" +AddValue="%1 əlavə et" AlreadyRunning.Title="OBS artıq işləyir" +AlreadyRunning.Text="OBS artıq işləyir! Bunu etmək istəmirsinizsə, zəhmət olmasa yeni bir nümunəni işlətməyi sınamazdan əvvəl bütün mövcud OBS nümunələrini söndürün. OBS-i sistem sinisinə kiçilməsi üçün tənzimləmisinizsə, zəhmət olmasa işlədiyini görmək üçün yoxlayın." AlreadyRunning.LaunchAnyway="Yenə də başlat" +ChromeOS.Title="Dəstəklənməyən platform" +ChromeOS.Text="OBS ChromeOS konteyneri içində işləyir kimi görünür. Bu platform dəstəklənmir" +DockCloseWarning.Title="Qoşulan pəncərəni bağla" +DockCloseWarning.Text="İndicə qoşulan pəncərəni bağladınız. Əgər yenidən göstərmək istəyirsinizsə, Menyu sətrindəki Bax → Yuvalar bölməsinə gedin." +ExtraBrowsers="Özəl Səyyah Yuvaları" Auth.Authing.Title="Kimlik təsdiqlənir..." Auth.Authing.Text="%1 ilə təsdiqlənir, zəhmət olmasa gözləyin..." @@ -250,11 +272,15 @@ Basic.Main.AddSceneCollection.Title="Səhnə Kolleksiyası Əlavə et" +Basic.MainMenu.View="Bax (&V)" +Basic.MainMenu.Help.Logs.ViewCurrentLog="Hazırki jurnala bax (&V)" +Basic.Settings.General.Preview="Önbaxış" + Basic.Settings.Stream.TTVAddon.None="Heç biri" @@ -269,28 +295,128 @@ Basic.Settings.Stream.TTVAddon.None="Heç biri" Basic.Settings.Advanced.General.ProcessPriority.AboveNormal="Normaldan Üstün" Basic.Settings.Advanced.General.ProcessPriority.Normal="Normal" Basic.Settings.Advanced.General.ProcessPriority.BelowNormal="Normaldan Aşağı" +Basic.Settings.Advanced.Hotkeys.DisableHotkeysInFocus="Əsas pəncərə fokusda olan zaman qısayol düymələrini sıradan çıxart" +Basic.Settings.Advanced.Hotkeys.DisableHotkeysOutOfFocus="Əsas pəncərə fokusda olmayan zaman qısayol düymələrini sıradan çıxart" +Basic.Settings.Advanced.AutoRemux="Avtomatik olaraq mp4-ə remux et" +Basic.Settings.Advanced.AutoRemux.MP4="(mkv kimi yaz)" +Basic.AdvAudio="Qabaqcıl Səs Xüsusiyyətləri" +Basic.AdvAudio.ActiveOnly="Yalnız Aktiv Mənbələr" +Basic.AdvAudio.Name="Ad" +Basic.AdvAudio.Volume="Səs səviyyəsi" Basic.AdvAudio.Mono="Mono" -Basic.AdvAudio.Monitoring.None="Monitor Sönüb" - - - - - - - - - - - - - - - - - +Basic.AdvAudio.Balance="Balans" +Basic.AdvAudio.Monitoring="Səs İzləmə" +Basic.AdvAudio.Monitoring.None="Ekran bağlıdır" +Basic.AdvAudio.Monitoring.MonitorOnly="Yalnız ekran (səssiz çıxış)" +Basic.AdvAudio.Monitoring.Both="Ekran və çıxış" +Basic.AdvAudio.AudioTracks="Treklər" + +Basic.Settings.Hotkeys="Qısayollar" +Basic.Settings.Hotkeys.Filter="Filtr" + +Basic.Hotkeys.SelectScene="Səhnəyə keç" + +Basic.SystemTray.Show="Göstər" +Basic.SystemTray.Hide="Gizlət" + +Basic.SystemTray.Message.Reconnecting="Bağlantı kəsildi. Yenidən bağlantı qurulur..." + +Hotkeys.Insert="Daxil et" +Hotkeys.Delete="Sil" +Hotkeys.Home="Əsas səhifə" +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="Sol" +Hotkeys.Right="Sağ" +Hotkeys.Up="Yuxarı" +Hotkeys.Down="Aşağı" +Hotkeys.Windows="Windows" +Hotkeys.Super="Super" +Hotkeys.Menu="Menyu" +Hotkeys.Space="Boşluq" +Hotkeys.AppleKeypadNum="%1 (Keypad)" +Hotkeys.AppleKeypadMultiply="* (Keypad)" +Hotkeys.AppleKeypadDivide="/ (Keypad)" +Hotkeys.AppleKeypadAdd="+ (Keypad)" +Hotkeys.AppleKeypadSubtract="- (Keypad)" +Hotkeys.AppleKeypadDecimal=". (Keypad)" +Hotkeys.AppleKeypadEqual="= (Keypad)" +Hotkeys.MouseButton="%1 Siçan" +Hotkeys.Escape="Esc" + +Mute="Səsi kəs" +Unmute="Səsi aç" +Push-to-mute="Basanda səsi kəs" +Push-to-talk="Bas, danış" + +SceneItemShow="'%1' göstər" +SceneItemHide="'%1' gizlət" + +OutputWarnings.NoTracksSelected="Ən azı bir trek seçməlisiniz" + +FinalScene.Title="Səhnəni sil" +FinalScene.Text="Ən azı bir səhnə olmalıdır." + +NoSources.Title="Mənbələr yoxdur" +NoSources.Text="Deyəsən hələ də heç bir video mənbəsi əlavə etməmisiniz, ona görə də çıxışda sadəcə boş bir ekran olacaq. Bunu etmək istədiyinizə əminsiniz?" +NoSources.Text.AddSource="İstənilən vaxt əsas pəncərədə Mənbələr qutusunun altındakı + nişanına klikləyərək mənbələr əlavə edə bilərsiniz." +NoSources.Label="Heç bir mənbəniz yoxdur.\nAşağıdakı + düyməsinə klikləyərək və ya sağ klikləyərək birini əlavə edin." + +ChangeBG="Rəngi tənzimlə" +CustomColor="Özəl rəng" + +BrowserSource.EnableHardwareAcceleration="Səyyah Mənbə Avandanlıq Təminatı Sürətləndirməsini Fəallaşdır" + +About="Haqqında" +About.Info="OBS Studio ödənişsiz və açıq mənbəli video yazma və canlı yayım proqram təminatıdır." +About.Donate="Töhfə ver" +About.GetInvolved="Qoşulun" +About.Authors="Müəlliflər" +About.License="Lisenziya" +About.Contribute="OBS layihəsini dəstəklə" + +AddUrl.Title="URL ilə mənbə əlavə et" +AddUrl.Text="URL-ni OBS-a gətirdiniz. Bu, bağlantını avtomatik olaraq mənbə kimi əlavə edəcəkdir. Davam edilsin?" +AddUrl.Text.Url="URL: %1" + +ResizeOutputSizeOfSource="Çıxışı yenidən ölçüləndir (mənbə ölçüsü)" +ResizeOutputSizeOfSource.Text="Təməl və çıxış ölçüləri mövcud mənbənin ölçülərinə görə yenidən ölçüləndiriləcək." +ResizeOutputSizeOfSource.Continue="Davam etmək istəyirsiniz?" + +PreviewTransition="Əvvəlki keçid" + +Importer="Səhnə Kolleksiya İdxalçısı" +Importer.SelectCollection="Səhnə kolleksiyası seç" +Importer.Collection="Səhnə Kolleksiyası" +Importer.HelpText="OBS və ya digər dəstəklənən proqramlardan bu pəncərəyə idxal etmək üçün fayllar əlavə edin." +Importer.Path="Kolleksiya Yolu" +Importer.Program="Aşkarlanan Tətbiqetmə" +Importer.AutomaticCollectionPrompt="Səhnə Kolleksiyaları üçün Avtomatik Axtarış" +Importer.AutomaticCollectionText="OBS, dəstəklənən üçüncü tərəf proqramlardan idxal edilə bilən səhnə kolleksiyalarını avtomatik olaraq tapa bilər. OBS-in səhnə kolleksiyalarını sizin üçün avtomatik tapmağını istəyirsiniz?\n\nBunu daha sonra Tənzimləmələr > Ümumi > İdxalçılar bölməsində dəyişdirə bilərsiniz." +Restart="Yenidən başlat" +NeedsRestart="OBS Studio yenidən başladılmalıdır. İndi yenidən başlatmaq istəyirsiniz?" +ContextBar.NoSelectedSource="Mənbə seçilməyib" +ContextBar.ResetTransform="Çevrilməni sıfırla" +ContextBar.FitToCanvas="Kətana uyğun" +ContextBar.MediaControls.PlayMedia="Medianı oynat" +ContextBar.MediaControls.PauseMedia="Mediaya fasilə ver" +ContextBar.MediaControls.StopMedia="Medianı dayandır" +ContextBar.MediaControls.RestartMedia="Medianı yenidən başlat" +ContextBar.MediaControls.PlaylistNext="Oynatma siyahısında növbəti" +ContextBar.MediaControls.PlaylistPrevious="Oynatma siyahısında əvvəlki" +ContextBar.MediaControls.MediaProperties="Media xüsusiyyətləri" +ContextBar.MediaControls.BlindSeek="Media axtarış viceti" diff --git a/UI/data/locale/ba-RU.ini b/UI/data/locale/ba-RU.ini index 5b46173..5fbbc84 100644 --- a/UI/data/locale/ba-RU.ini +++ b/UI/data/locale/ba-RU.ini @@ -88,6 +88,8 @@ Windowed="Тәҙрә үтәмлеге" Percent="Проценттар" AspectRatio="%1:%2 яҡтарҙың мөнәсәбәттәре" LockVolume="Тауышты билдәләү" +OpenFile="Файл асырға" +AddValue="Өҫтәргә: %1" AlreadyRunning.Title="OBS ҡабыҙылған инде" AlreadyRunning.LaunchAnyway="Барабер ебәреү" @@ -178,6 +180,7 @@ Basic.RemoveTransition="Көйләүле әүрелеүҙе юйырға" Basic.TransitionDuration="Оҙайлыҡ" +TitleBar.Profile="Профиль" TitleBar.Scenes="Сәхнәләр" @@ -225,6 +228,7 @@ Basic.Main.DefaultSceneName.Text="Сәхнә %1" + Basic.Filters="Фильтрҙар" Basic.Filters.AddFilter.Title="Фильтр исеме" @@ -240,6 +244,7 @@ Basic.MainMenu.File.Export="Экспорт (&E)" Basic.MainMenu.File.Import="Импорт (&I)" Basic.MainMenu.File.Remux="Яҙмаларҙың ремукслау (&M)" Basic.MainMenu.File.Settings="Көйләүҙәр (&S)" +Basic.MainMenu.File.Exit="Сығыу (&X)" Basic.MainMenu.View.SceneTransitions="Сәхнә әүрелеүҙәре (&C)" diff --git a/UI/data/locale/bg-BG.ini b/UI/data/locale/bg-BG.ini index 82ab671..aca11ff 100644 --- a/UI/data/locale/bg-BG.ini +++ b/UI/data/locale/bg-BG.ini @@ -318,8 +318,6 @@ Deinterlacing.Yadif2x="Ядиф 2x (Yadif 2x)" Deinterlacing.TopFieldFirst="Първо горното поле" Deinterlacing.BottomFieldFirst="Първо долното поле" -VolControl.SliderUnmuted="Плъзгач за сила на звука '%1': %2" -VolControl.SliderMuted="Плъзгач за сила на звука '%1': %2 (текущо заглушен)" VolControl.Mute="Заглуши '%1'" VolControl.Properties="Свойства на '%1'" @@ -349,6 +347,7 @@ Basic.SourceSelect.CreateNew="Създай нов" Basic.SourceSelect.AddExisting="Добави съществуващ" Basic.SourceSelect.AddVisible="Направете видим източника" + Basic.PropertiesWindow="Свойства на '%1'" Basic.PropertiesWindow.AutoSelectFormat="%1 (автоматично: %2)" Basic.PropertiesWindow.SelectColor="Избор на цвят" @@ -570,7 +569,6 @@ 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="Допълнителни настройки" @@ -587,8 +585,6 @@ 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="Предупреждение: Оригиналното качество създава огромни файлове! Запис настроен на Оригинално качество може да заема над 7GB дисково пространство на минута, ако резолюцията и кадрите са високи. Не се препоръчва ако не разполагате със много пространство." Basic.Settings.Output.Simple.Warn.Lossless.Msg="Сигурни ли сте че искате да ползвате оригиналното качество на записа?" @@ -610,7 +606,6 @@ 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" diff --git a/UI/data/locale/bn-BD.ini b/UI/data/locale/bn-BD.ini index a002540..3c91812 100644 --- a/UI/data/locale/bn-BD.ini +++ b/UI/data/locale/bn-BD.ini @@ -198,8 +198,6 @@ Deinterlacing.Yadif2x="Yadif 2 x" Deinterlacing.TopFieldFirst="প্রথম ক্ষেত্রে শীর্ষ" Deinterlacing.BottomFieldFirst="মাঠে প্রথমে নীচের" -VolControl.SliderUnmuted="'%1'-এর জন্য ভলিয়ুম স্লাইডার: %2" -VolControl.SliderMuted="'%1'-এর জন্য ভলিয়ুম স্লাইডার: %2 (বর্তমানে মিউট করা)" VolControl.Mute="কথা বলতে পারে '%1 '" VolControl.Properties="'%1'-এর জন্য বৈশিষ্ট্যসমূহ" @@ -227,6 +225,7 @@ Basic.SourceSelect.CreateNew="নতুন তৈরি করুন" Basic.SourceSelect.AddExisting="বর্তমান যুক্ত করুন" Basic.SourceSelect.AddVisible="উৎস করে প্রদর্শিত" + Basic.PropertiesWindow="'%1'-এর জন্য বৈশিষ্ট্যসমূহ" Basic.PropertiesWindow.AutoSelectFormat="%1 (স্বয়ংনির্বাচন: %2)" Basic.PropertiesWindow.SelectColor="রঙ নির্বাচন করুন" @@ -410,7 +409,6 @@ Basic.Settings.Output.Format="আমল লেখকবৃন্দ বিন্ Basic.Settings.Output.Encoder="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="অ্যাডভান্সড" diff --git a/UI/data/locale/ca-ES.ini b/UI/data/locale/ca-ES.ini index 392284f..53813d7 100644 --- a/UI/data/locale/ca-ES.ini +++ b/UI/data/locale/ca-ES.ini @@ -161,6 +161,7 @@ Basic.AutoConfig.StreamPage.DisconnectAccount="Desconnecta el compte" Basic.AutoConfig.StreamPage.DisconnectAccount.Confirm.Title="Voleu desconnectar el compte?" Basic.AutoConfig.StreamPage.DisconnectAccount.Confirm.Text="Aquest canvi s'aplicarà immediatament. Segur que voleu desconnectar el compte?" Basic.AutoConfig.StreamPage.GetStreamKey="Obté una clau" +Basic.AutoConfig.StreamPage.MoreInfo="Més informació" Basic.AutoConfig.StreamPage.UseStreamKey="Utilitza una clau de transmissió" Basic.AutoConfig.StreamPage.Service="Servei" Basic.AutoConfig.StreamPage.Service.ShowAll="Mostra-ho tot..." @@ -209,7 +210,7 @@ Basic.Stats.Status.Inactive="Inactiu" Basic.Stats.Status.Active="Actiu" Basic.Stats.DroppedFrames="Fotogrames perduts (xarxa)" Basic.Stats.MegabytesSent="Sortida de dades total" -Basic.Stats.Bitrate="Tassa de bits" +Basic.Stats.Bitrate="Taxa de bits" Basic.Stats.DiskFullIn="Disc ple en (aprox.)" Basic.Stats.ResetStats="Reinicia les estadístiques" @@ -365,8 +366,8 @@ Deinterlacing.Yadif2x="Yadif 2x" Deinterlacing.TopFieldFirst="Camp superior primer" Deinterlacing.BottomFieldFirst="Camp inferior primer" -VolControl.SliderUnmuted="Control lliscant del volum per '%1': %2" -VolControl.SliderMuted="Control lliscant del volum per '%1': %2 (silenciat)" +VolControl.SliderUnmuted="Control lliscant del volum per a '%1':" +VolControl.SliderMuted="Control lliscant del volum per a '%1': (silenciat)" VolControl.Mute="Silencia '%1'" VolControl.Properties="Propietats per '%1'" @@ -382,6 +383,7 @@ Basic.Main.RenameSceneCollection.Title="Canvia el nom de col·lecció de l'escen AddProfile.Title="Afegeix un perfil" AddProfile.Text="Introduïu el nom del perfil" +AddProfile.WizardCheckbox="Mostra l'assistent automàtic de configuració" RenameProfile.Title="Canvia el nom del perfil" @@ -396,6 +398,11 @@ Basic.SourceSelect.CreateNew="Crea" Basic.SourceSelect.AddExisting="Afegeix-ne una d'existent" Basic.SourceSelect.AddVisible="Fes visible l'origen" +Basic.Main.Sources.Visibility="Visibilitat" +Basic.Main.Sources.VisibilityDescription="Controla la visibilitat de '%1' al llenç" +Basic.Main.Sources.Lock="Bloca" +Basic.Main.Sources.LockDescription="Bloca la posició i l'escala de '%1' al llenç" + Basic.PropertiesWindow="Propietats de «%1»" Basic.PropertiesWindow.AutoSelectFormat="%1 (autoselecció: %2)" Basic.PropertiesWindow.SelectColor="Seleccioneu un color" @@ -635,13 +642,19 @@ Basic.Settings.Stream.StreamSettingsWarning="Obre la configuració" Basic.Settings.Stream.MissingUrlAndApiKey="Falta l'URL i la clau de transmissió.\n\nObriu la configuració per introduir l'URL i la clau de transmissió a la pestanya «transmissió»." Basic.Settings.Stream.MissingUrl="Falta l'URL de la transmissió.\n\nObriu la configuració per introduir l'URL a la pestanya «transmissió»." Basic.Settings.Stream.MissingStreamKey="Falta la clau de transmissió.\n\nObriu la configuració per introduir la clau de transmissió a la pestanya «transmissió»." +Basic.Settings.Stream.IgnoreRecommended="Ignora la configuració recomanada del servei de retransmissió" +Basic.Settings.Stream.IgnoreRecommended.Warn.Title="Ignora la configuració recomanada" +Basic.Settings.Stream.IgnoreRecommended.Warn.Text="Atenció: Ignorar els límits del servei pot donar com a resultat una degradació o bandejament de la retransmissió.\n\nSegur que voleu continuar?" +Basic.Settings.Stream.Recommended.MaxVideoBitrate="Taxa de bits màxima de vídeo: %1 kbps" +Basic.Settings.Stream.Recommended.MaxAudioBitrate="Taxa de bits màxima d'àudio: %1 kbps" +Basic.Settings.Stream.Recommended.MaxResolution="Resolució màxima: %1" +Basic.Settings.Stream.Recommended.MaxFPS="FPS màxims: %1" Basic.Settings.Output="Sortida" Basic.Settings.Output.Format="Format d'enregistrament" Basic.Settings.Output.Encoder="Codificador" Basic.Settings.Output.SelectDirectory="Seleccioneu el directori de gravació" Basic.Settings.Output.SelectFile="Seleccioni l'arxiu de gravació" -Basic.Settings.Output.EnforceBitrate="Forçar límits de tassa de bits al servei d'streaming" Basic.Settings.Output.DynamicBitrate="Canvia dinàmicament la ràtio per manegar la saturació" Basic.Settings.Output.DynamicBitrate.Beta="Canvia dinàmicament la ràtio per manegar la saturació (Beta)" Basic.Settings.Output.DynamicBitrate.TT="En comptes de perdre fotogrames per reduir la saturació, canvia dinàmicament la ràtio al vol.\n\nTingueu en compte que això pot incrementar el retard per als espectadors si hi ha cap saturació important.\nEn baixar la ràtio, pot trigar uns minuts a restaurar el valor original.\n\nActualment només suportat per a RTMP." @@ -662,8 +675,8 @@ Basic.Settings.Output.Simple.RecordingQuality.Stream="Mateixa que en directe" Basic.Settings.Output.Simple.RecordingQuality.Small="Qualitat alta, mida d'arxiu mitjana" Basic.Settings.Output.Simple.RecordingQuality.HQ="Qualitat molt elevada, mida de fitxer gran" Basic.Settings.Output.Simple.RecordingQuality.Lossless="Qualitat sense pèrdues, mida de l'arxiu molt gran" -Basic.Settings.Output.Simple.Warn.VideoBitrate="ADVERTÈNCIA: La transmissió del vídeo s'establirà a %1, que és el límit superior per al servei de streaming actual. Si està segur que vol anar per sobre de %1, activi les opcions avançades del codificador i desactivi \"Forçar límits de tassa de bits al servei d'streaming\"." -Basic.Settings.Output.Simple.Warn.AudioBitrate="ADVERTÈNCIA: La transmissió d'àudio s'establirà a %1, que és el límit superior per al servei de streaming actual. Si està segur que vol anar per sobre de %1, activi les opcions avançades del codificador i desactivi \"Forçar límits de tassa de bits al servei d'streaming\"." +Basic.Settings.Output.Simple.Warn.VideoBitrate="Atenció: La taxa de bits de vídeo s’establirà a %1, que és el límit superior per al servei de transmissió actual." +Basic.Settings.Output.Simple.Warn.AudioBitrate="Atenció: La taxa de bits d'àudio s’establirà a %1, que és el límit superior per al servei de transmissió actual." Basic.Settings.Output.Simple.Warn.CannotPause="Atenció: No es poden pausar els enregistraments si la qualitat està configurada a «Mateixa que en directe»." Basic.Settings.Output.Simple.Warn.Encoder="Advertiment: Gravar amb un software codificador en una qualitat diferent que el directe requerirà ús de CPU addicional si el directe i la gravació es fan a la vegada." Basic.Settings.Output.Simple.Warn.Lossless="Advertiment: La qualitat sense pèrdues genera mides d'arxiu gegantines! La qualitat sense pèrdues pot utilitzar un total de 7 gigabytes d'espai de disc per minut a alta resolució i FPS. Aquesta qualitat no és recomanable per a enregistraments llargs llevat que tingui una gran quantitat d'espai de disc disponible." @@ -674,6 +687,11 @@ Basic.Settings.Output.Simple.Encoder.Hardware.QSV="Maquinari (QSV)" Basic.Settings.Output.Simple.Encoder.Hardware.AMD="Maquinari (AMD)" Basic.Settings.Output.Simple.Encoder.Hardware.NVENC="Maquinari (NVENC)" Basic.Settings.Output.Simple.Encoder.SoftwareLowCPU="Programari (preconfiguració de x264 amb baix ús de CPU, augmenta la mida del fitxer)" +Basic.Settings.Output.Simple.TwitchVodTrack="Pista VOD del Twitch (utilitza la pista 2)" +Basic.Settings.Output.Warn.EnforceResolutionFPS.Title="Resolució o velocitat de fotogrames incompatible" +Basic.Settings.Output.Warn.EnforceResolutionFPS.Msg="Aquest servei de reproducció en temps real no admet la vostra resolució de sortida i/o velocitat de fotogrames actuals. Es canviaran al valor compatible més proper:\n\n%1\n\nVoleu continuar?" +Basic.Settings.Output.Warn.EnforceResolutionFPS.Resolution="Resolució: %1" +Basic.Settings.Output.Warn.EnforceResolutionFPS.FPS="FPS: %1" Basic.Settings.Output.VideoBitrate="Bitrate de vídeo" Basic.Settings.Output.AudioBitrate="Bitrate d'àudio" Basic.Settings.Output.Reconnect="Torna a connectar automàticament" @@ -688,15 +706,16 @@ Basic.Settings.Output.NoSpaceFileName="Generar nom de fitxer sense espai" Basic.Settings.Output.Adv.Rescale="Reescala la sortida" Basic.Settings.Output.Adv.AudioTrack="Pista d'àudio" Basic.Settings.Output.Adv.Streaming="Directe" -Basic.Settings.Output.Adv.ApplyServiceSettings="Forçar configuracions del codificador de servei de directe" Basic.Settings.Output.Adv.Audio.Track1="Pista 1" Basic.Settings.Output.Adv.Audio.Track2="Pista 2" Basic.Settings.Output.Adv.Audio.Track3="Pista 3" Basic.Settings.Output.Adv.Audio.Track4="Pista 4" Basic.Settings.Output.Adv.Audio.Track5="Pista 5" Basic.Settings.Output.Adv.Audio.Track6="Pista 6" +Basic.Settings.Output.Adv.TwitchVodTrack="Pista VOD del Twitch" Basic.Settings.Output.Adv.Recording="Enregistrament" +Basic.Settings.Output.Adv.Recording.RecType="Tipus de gravació" Basic.Settings.Output.Adv.Recording.Type="Tipus" Basic.Settings.Output.Adv.Recording.Type.Standard="Estàndard" Basic.Settings.Output.Adv.Recording.Type.FFmpegOutput="Sortida personalitzada (FFmpeg)" @@ -824,13 +843,18 @@ Basic.AdvAudio="&Propietats avançades d'àudio" Basic.AdvAudio.ActiveOnly="Només fonts actives" Basic.AdvAudio.Name="Nom" Basic.AdvAudio.Volume="Volum" +Basic.AdvAudio.VolumeSource="Volum per a '%1'" Basic.AdvAudio.Mono="Mono" +Basic.AdvAudio.MonoSource="Mescla monoaural per a '%1'" Basic.AdvAudio.Balance="Balanç" +Basic.AdvAudio.BalanceSource="Balanç per a '%1'" Basic.AdvAudio.SyncOffset="Correcció de sincronització" +Basic.AdvAudio.SyncOffsetSource="Compensació de sincronisme per a '%1'" Basic.AdvAudio.Monitoring="Monitorització d'àudio" Basic.AdvAudio.Monitoring.None="Monitorització desactivada" Basic.AdvAudio.Monitoring.MonitorOnly="Només monitorizació (silencia la sortida)" Basic.AdvAudio.Monitoring.Both="Monitorització i sortida" +Basic.AdvAudio.MonitoringSource="Monitorització d'àudio per a '%1'" Basic.AdvAudio.AudioTracks="Pistes" Basic.Settings.Hotkeys="Dreceres de teclat" diff --git a/UI/data/locale/cs-CZ.ini b/UI/data/locale/cs-CZ.ini index 053e4ef..a18d897 100644 --- a/UI/data/locale/cs-CZ.ini +++ b/UI/data/locale/cs-CZ.ini @@ -161,6 +161,7 @@ Basic.AutoConfig.StreamPage.DisconnectAccount="Odpojit účet" Basic.AutoConfig.StreamPage.DisconnectAccount.Confirm.Title="Odpojení účtu" Basic.AutoConfig.StreamPage.DisconnectAccount.Confirm.Text="Tato změna proběhne okamžitě. Opravdu si přejete odpojit účet ?" Basic.AutoConfig.StreamPage.GetStreamKey="Získat vysílací klíč" +Basic.AutoConfig.StreamPage.MoreInfo="Více informací" Basic.AutoConfig.StreamPage.UseStreamKey="Použít vysílací klíč" Basic.AutoConfig.StreamPage.Service="Služba" Basic.AutoConfig.StreamPage.Service.ShowAll="Zobrazit vše..." @@ -365,8 +366,8 @@ Deinterlacing.Yadif2x="Yadif 2x" Deinterlacing.TopFieldFirst="Svrchní řádek dříve" Deinterlacing.BottomFieldFirst="Spodní řádek dříve" -VolControl.SliderUnmuted="Posuvník hlasitosti pro '%1': %2" -VolControl.SliderMuted="Posuvník hlasitosti pro '%1': %2 (ztlumeno)" +VolControl.SliderUnmuted="Posuvník hlasitosti pro '%1':" +VolControl.SliderMuted="Posuvník hlasitosti pro '%1': (aktuálně ztlumeno)" VolControl.Mute="Ztlumit '%1'" VolControl.Properties="Vlastnosti pro \"%1\"" @@ -382,6 +383,7 @@ Basic.Main.RenameSceneCollection.Title="Přejmenování kolekce scén" AddProfile.Title="Přidání profilu" AddProfile.Text="Zadejte prosím jméno profilu" +AddProfile.WizardCheckbox="Zobrazit Průvodce nastavením" RenameProfile.Title="Přejmenování profilu" @@ -396,6 +398,11 @@ Basic.SourceSelect.CreateNew="Vytvořit nový" Basic.SourceSelect.AddExisting="Přidat existující" Basic.SourceSelect.AddVisible="Zviditelnit zdroj" +Basic.Main.Sources.Visibility="Viditelnost" +Basic.Main.Sources.VisibilityDescription="Ovládá viditelnost zdroje '%1' v editoru" +Basic.Main.Sources.Lock="Zamknout" +Basic.Main.Sources.LockDescription="Uzamkne pozici a velikost zdroje '%1' v editoru" + Basic.PropertiesWindow="Vlastnosti objektu '%1'" Basic.PropertiesWindow.AutoSelectFormat="%1 (automatické: %2)" Basic.PropertiesWindow.SelectColor="Výběr barvy" @@ -635,13 +642,19 @@ Basic.Settings.Stream.StreamSettingsWarning="Otevřít nastavení" Basic.Settings.Stream.MissingUrlAndApiKey="Chybí vysílací klíč a adresa.\n\nPro nastavení klíče a adresy otevřete nastavení na záložce 'Vysílání'." Basic.Settings.Stream.MissingUrl="Chybí vysílací adresa.\n\nPro nastavení adresy otevřete nastavení na záložce 'Vysílání'." Basic.Settings.Stream.MissingStreamKey="Chybí vysílací klíč.\n\nPro nastavení klíče otevřete nastavení na záložce 'Vysílání'." +Basic.Settings.Stream.IgnoreRecommended="Ignorovat doporučená nastavení vysílací služby" +Basic.Settings.Stream.IgnoreRecommended.Warn.Title="Přepsat doporučená nastavení" +Basic.Settings.Stream.IgnoreRecommended.Warn.Text="Varování: Ignorování limitací služby může způsobit sníženou kvalitu vysílání nebo úplně zabránit vysílání.\n\nChcete pokračovat ?" +Basic.Settings.Stream.Recommended.MaxVideoBitrate="Maximální bitrate videa: %1 kbps" +Basic.Settings.Stream.Recommended.MaxAudioBitrate="Maximální bitrate zvuku: %1 kbps" +Basic.Settings.Stream.Recommended.MaxResolution="Maximální rozlišení: %1" +Basic.Settings.Stream.Recommended.MaxFPS="Maximální FPS: %1" Basic.Settings.Output="Výstup" Basic.Settings.Output.Format="Formát nahrávání" Basic.Settings.Output.Encoder="Enkodér" Basic.Settings.Output.SelectDirectory="Vyberte složku pro nahrávání" Basic.Settings.Output.SelectFile="Vyberte soubor pro nahrávání" -Basic.Settings.Output.EnforceBitrate="Vynutit omezení bitratu streamovací služby" Basic.Settings.Output.DynamicBitrate="Dynamicky měnit bitrate v závislosti na zahlcení sítě" Basic.Settings.Output.DynamicBitrate.Beta="Dynamicky měnit bitrate v závislosti na zahlcení sítě (Beta)" Basic.Settings.Output.DynamicBitrate.TT="Místo zahazování snímků, pro snížení zahlcení sítě, bude průběžně měněn bitrate.\n\nMějte na vědomí, že se může zvýšit odezva pro diváky, pokud dojde k náhlému zahlcení sítě.\nPo snížení bitratu to může trvat pár minut, než se zase navýší.\n\nZatím je podporováno pouze RTMP." @@ -662,8 +675,8 @@ Basic.Settings.Output.Simple.RecordingQuality.Stream="Stejná jako vysílaná" Basic.Settings.Output.Simple.RecordingQuality.Small="Vysoká kvalita, střední velikost souboru" Basic.Settings.Output.Simple.RecordingQuality.HQ="Nerozeznatelný pokles kvality, velké soubory" Basic.Settings.Output.Simple.RecordingQuality.Lossless="Lossless, obrovské soubory" -Basic.Settings.Output.Simple.Warn.VideoBitrate="Varování: Bitrate videa bude nastaven %1, což je maximum, které tato streamovací služba umožňuje. Pokud si jste jisti, že chcete tento limit překročit, povolte rožšířené možnosti enkodéru a odškrtněte \"Vynutit omezení bitratu streamovací služby\"." -Basic.Settings.Output.Simple.Warn.AudioBitrate="Varování: Bitrate zvuku bude nastaven %1, což je maximum, které tato streamovací služba umožňuje. Pokud si jste jisti, že chcete tento limit překročit, povolte rožšířené možnosti enkodéru a odškrtněte \"Vynutit omezení bitratu streamovací služby\"." +Basic.Settings.Output.Simple.Warn.VideoBitrate="Varování: Bitrate vysílaného videa bude nastaven na %1, což je horní mez pro aktuální vysílací službu." +Basic.Settings.Output.Simple.Warn.AudioBitrate="Varování: Bitrate vysílaného zvuku bude nastaven na %1, což je horní mez pro aktuální vysílací službu." Basic.Settings.Output.Simple.Warn.CannotPause="Varování: Nahrávání není možné pozastavit, pokud je nahrávací kvalita nastavena na \"Stejná jako vysílaná\"." Basic.Settings.Output.Simple.Warn.Encoder="Varování: Nahrávání se softwarovým enkodérem v jiné kvalitě než je vysílaná bude CPU využívat více, pokud budete vysílat a nahrávat současně." Basic.Settings.Output.Simple.Warn.Lossless="Varování: Při použití této kvality budou výsledné nahrávky obrovské! Při použití vysokého rozlišení a snímkování mohou využít až 7 GB diskového prostoru za minutu nahrávky. Tato kvalita není doporučena pro dlouhé nahrávky, pokud nemáte opravdu velký volný prostor na disku." @@ -674,6 +687,11 @@ Basic.Settings.Output.Simple.Encoder.Hardware.QSV="Hardwarový (QSV)" Basic.Settings.Output.Simple.Encoder.Hardware.AMD="Hardwarový (AMD)" Basic.Settings.Output.Simple.Encoder.Hardware.NVENC="Hardwarový (NVENC)" Basic.Settings.Output.Simple.Encoder.SoftwareLowCPU="Softwarový (x264 předvolba nízkého zatížení CPU, větší soubory)" +Basic.Settings.Output.Simple.TwitchVodTrack="Stopa Twitch VOD (používá stopu 2)" +Basic.Settings.Output.Warn.EnforceResolutionFPS.Title="Nekompatibilní rozlišení/FPS" +Basic.Settings.Output.Warn.EnforceResolutionFPS.Msg="Tato vysílací služba nepodporuje aktuálně vybrané rozlišení anebo FPS. Budou změněny na nejbližší kompatibilní hodnoty:\n\n%1\n\nOpravdu chcete pokračovat ?" +Basic.Settings.Output.Warn.EnforceResolutionFPS.Resolution="Rozlišení: %1" +Basic.Settings.Output.Warn.EnforceResolutionFPS.FPS="FPS: %1" Basic.Settings.Output.VideoBitrate="Bitrate videa" Basic.Settings.Output.AudioBitrate="Bitrate zvuku" Basic.Settings.Output.Reconnect="Automaticky obnovit spojení" @@ -688,15 +706,16 @@ Basic.Settings.Output.NoSpaceFileName="Generovat název souboru bez mezery" Basic.Settings.Output.Adv.Rescale="Přeškálovat výstup" Basic.Settings.Output.Adv.AudioTrack="Zvuková stopa" Basic.Settings.Output.Adv.Streaming="Vysílání" -Basic.Settings.Output.Adv.ApplyServiceSettings="Přikázat vysílací službě použití nastavení enkodéru" Basic.Settings.Output.Adv.Audio.Track1="Stopa 1" Basic.Settings.Output.Adv.Audio.Track2="Stopa 2" Basic.Settings.Output.Adv.Audio.Track3="Stopa 3" Basic.Settings.Output.Adv.Audio.Track4="Stopa 4" Basic.Settings.Output.Adv.Audio.Track5="Stopa 5" Basic.Settings.Output.Adv.Audio.Track6="Stopa 6" +Basic.Settings.Output.Adv.TwitchVodTrack="Stopa Twitch VOD" Basic.Settings.Output.Adv.Recording="Nahrávání" +Basic.Settings.Output.Adv.Recording.RecType="Typ záznamu" Basic.Settings.Output.Adv.Recording.Type="Typ" Basic.Settings.Output.Adv.Recording.Type.Standard="Standardní" Basic.Settings.Output.Adv.Recording.Type.FFmpegOutput="Vlastní výstup (FFmpeg)" @@ -824,13 +843,18 @@ Basic.AdvAudio="Rozšířené vlastnosti zvuku" Basic.AdvAudio.ActiveOnly="Pouze aktivní zdroje" Basic.AdvAudio.Name="Název" Basic.AdvAudio.Volume="Hlasitost" +Basic.AdvAudio.VolumeSource="Hlasitost pro '%1'" Basic.AdvAudio.Mono="Mono" +Basic.AdvAudio.MonoSource="Mono Downmix pro '%1'" Basic.AdvAudio.Balance="Vyvážení" +Basic.AdvAudio.BalanceSource="Vyvážení pro '%1'" Basic.AdvAudio.SyncOffset="Zpoždění synchronizace" +Basic.AdvAudio.SyncOffsetSource="Synchronizační odsazení pro '%1'" Basic.AdvAudio.Monitoring="Monitorování zvuku" Basic.AdvAudio.Monitoring.None="Monitorování vypnuto" Basic.AdvAudio.Monitoring.MonitorOnly="Pouhé monitorování (ztlumit výstup)" Basic.AdvAudio.Monitoring.Both="Monitorovat a odesílat na výstup" +Basic.AdvAudio.MonitoringSource="Monitorování zvuku pro '%1'" Basic.AdvAudio.AudioTracks="Stopy" Basic.Settings.Hotkeys="Zkratky" @@ -907,7 +931,7 @@ CustomColor="Vlastní barva" BrowserSource.EnableHardwareAcceleration="Zapnout hardwarovou akceleraci pro zdroj prohlížeče" About="O aplikaci" -About.Info="OBS je otevřený software pro nahrávání videa a živé vysílání." +About.Info="OBS Studio je otevřený software pro nahrávání videa a živé vysílání." About.Donate="Přispět" About.GetInvolved="Zapojte se" About.Authors="Autoři" diff --git a/UI/data/locale/da-DK.ini b/UI/data/locale/da-DK.ini index a18f594..f92d500 100644 --- a/UI/data/locale/da-DK.ini +++ b/UI/data/locale/da-DK.ini @@ -161,6 +161,7 @@ Basic.AutoConfig.StreamPage.DisconnectAccount="Afbryd konto" Basic.AutoConfig.StreamPage.DisconnectAccount.Confirm.Title="Afbryde konto?" Basic.AutoConfig.StreamPage.DisconnectAccount.Confirm.Text="Denne ændring effektueres straks. Sikker på, at du vil afbryde din konto?" Basic.AutoConfig.StreamPage.GetStreamKey="Hent Streamnøgle" +Basic.AutoConfig.StreamPage.MoreInfo="Yderligere info" Basic.AutoConfig.StreamPage.UseStreamKey="Benyt Streamnøgle" Basic.AutoConfig.StreamPage.Service="Tjeneste" Basic.AutoConfig.StreamPage.Service.ShowAll="Vis alle..." @@ -365,8 +366,8 @@ Deinterlacing.Yadif2x="Yadif 2x" Deinterlacing.TopFieldFirst="Øverste felt først" Deinterlacing.BottomFieldFirst="Nederste felt først" -VolControl.SliderUnmuted="Lydstyrkeskyder til '%1': %2" -VolControl.SliderMuted="Lydstyrkeskyder til '%1': %2 (pt. på lydløs)" +VolControl.SliderUnmuted="Lydstyrkeskyder for '%1':" +VolControl.SliderMuted="Lydstyrkeskyder for '%1': (på lydløs i øjeblikket)" VolControl.Mute="Gør '%1' lydløs" VolControl.Properties="Egenskaber for '%1'" @@ -382,6 +383,7 @@ Basic.Main.RenameSceneCollection.Title="Omdøb scenesamling" AddProfile.Title="Tilføj profil" AddProfile.Text="Angiv profilens navn" +AddProfile.WizardCheckbox="Vis Auto-opsætningsguide" RenameProfile.Title="Omdøb profil" @@ -396,6 +398,11 @@ Basic.SourceSelect.CreateNew="Opret ny" Basic.SourceSelect.AddExisting="Tilføj eksisterende" Basic.SourceSelect.AddVisible="Gør kilde synlig" +Basic.Main.Sources.Visibility="Synlighed" +Basic.Main.Sources.VisibilityDescription="Styrer synligheden af '%1' på lærredet" +Basic.Main.Sources.Lock="Lås" +Basic.Main.Sources.LockDescription="Fastlåser position og skalering af '%1' på lærredet" + Basic.PropertiesWindow="Egenskaber for '%1'" Basic.PropertiesWindow.AutoSelectFormat="%1 (auto-vælg: %2)" Basic.PropertiesWindow.SelectColor="Vælg farve" @@ -635,13 +642,19 @@ Basic.Settings.Stream.StreamSettingsWarning="Åbn Indstillinger" Basic.Settings.Stream.MissingUrlAndApiKey="URL og Stream-nøgle mangler.\n\nÅbn Indstillinger for at angive URL og Stream-nøgle under 'Stream'-fanen." Basic.Settings.Stream.MissingUrl="Stream-URL mangler.\n\nÅbn Indstillinger for at angive URL'en under 'Stream'-fanen." Basic.Settings.Stream.MissingStreamKey="Stream-nøgle mangler.\n\nÅbn Indstillinger for at angive Stream-nøglen under 'Stream'-fanen." +Basic.Settings.Stream.IgnoreRecommended="Ignorér anbefalede indstillinger for streamingtjeneste" +Basic.Settings.Stream.IgnoreRecommended.Warn.Title="Tilsidesæt Anbefalede Indstillinger" +Basic.Settings.Stream.IgnoreRecommended.Warn.Text="Advarsel: Ignoreres tjenestebegrænsningerne, kan det resultere i forringet streamkvalitet eller forhindre dig i at streame.\n\nFortsæt?" +Basic.Settings.Stream.Recommended.MaxVideoBitrate="Maks. videobithastighed: %1 kbps" +Basic.Settings.Stream.Recommended.MaxAudioBitrate="Maks. audiobithastighed: %1 kbps" +Basic.Settings.Stream.Recommended.MaxResolution="Maks. opløsning: %1" +Basic.Settings.Stream.Recommended.MaxFPS="Maks. billeder/sekund (FPS): %1" Basic.Settings.Output="Output" Basic.Settings.Output.Format="Optagelsesformat" Basic.Settings.Output.Encoder="Encoder" Basic.Settings.Output.SelectDirectory="Vælg optagelsesmappe" Basic.Settings.Output.SelectFile="Vælg optagelsesfil" -Basic.Settings.Output.EnforceBitrate="Håndhæv streamingtjenestes bit-hastighedsbegrænsninger" Basic.Settings.Output.DynamicBitrate="Skift bithastighed dynamisk for at håndtere overbelastning" Basic.Settings.Output.DynamicBitrate.Beta="Skift bithastighed dynamisk for at håndtere overbelastning (Beta)" Basic.Settings.Output.DynamicBitrate.TT="I stedet for at droppe billeder for at reducere overbelastning, ændrer dette dynamisk bithastigheden løbende.\n\nBemærk at dette kan øge forsinkelsen, som seerne oplever, hvis der opstår betydelig pludselig overbelastning.\nNår bithastigheden falder, kan det tage op til et par få minutter for at gendanne den.\n\nKun RTMP understøttet pt." @@ -662,8 +675,8 @@ Basic.Settings.Output.Simple.RecordingQuality.Stream="Samme som stream" Basic.Settings.Output.Simple.RecordingQuality.Small="Høj kvalitet, medium filstørrelse" Basic.Settings.Output.Simple.RecordingQuality.HQ="Synlig identisk kvalitet, stor filstørrelse" Basic.Settings.Output.Simple.RecordingQuality.Lossless="Tabsfri kvalitet, enorm stor filstørrelse" -Basic.Settings.Output.Simple.Warn.VideoBitrate="Advarsel: Videostreamingbit-hastigheden sættes til %1, som er den øvre grænse for den aktuelle streamingtjeneste. Er du sikker på, at du vil at gå over %1, så aktivér avancerede encoder-valg og afmarkér \"Gennemtving streamingtjenestes bit-hastighedsbegrænsninger\"." -Basic.Settings.Output.Simple.Warn.AudioBitrate="Advarsel: Audiostreamingbit-hastigheden sættes til %1, som er den øvre grænse for den aktuelle streamingtjeneste. Er du sikker på, at du vil at gå over %1, så aktivér avancerede encoder-valg og afmarkér \"Gennemtving streamingtjenestes bit-hastighedsbegrænsninger\"." +Basic.Settings.Output.Simple.Warn.VideoBitrate="Advarsel: Streamingsvideobithastigheden indstilles til %1, som er den øvre grænse for den aktuelle streamingtjeneste." +Basic.Settings.Output.Simple.Warn.AudioBitrate="Advarsel: Streamingsaudiobithastigheden indstilles til %1, som er den øvre grænse for den aktuelle streamingtjeneste." Basic.Settings.Output.Simple.Warn.CannotPause="Advarsel: Optagelser kan ikke pauses, hvis optagekvaliteten er sat til \"Samme som strream\"." Basic.Settings.Output.Simple.Warn.Encoder="Advarsel: Optagelse med en software-encoder i en anden kvalitet end den streamede vil medføre ekstra CPU-forbrug, hvis du streamer og optager samtidigt." Basic.Settings.Output.Simple.Warn.Lossless="Advarsel: Tabsfri kvalitet genererer gevaldigt store filstørrelser! Tabsfri kvalitet kan forbruge op til 7 GB diskplads pr. minut ved høje opløsninger og billedhastigheder. Tabsfri tilstand anbefales ikke til lange optagelser, medmindre du har masser af tilgængelig diskplads." @@ -674,6 +687,11 @@ 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 lavt, forvalgt CPU-forbrug, øger filstørrelsen)" +Basic.Settings.Output.Simple.TwitchVodTrack="Twitch VOD-spor (Benytter Spor 2)" +Basic.Settings.Output.Warn.EnforceResolutionFPS.Title="Inkompatibel opløsning/billedhastighed" +Basic.Settings.Output.Warn.EnforceResolutionFPS.Msg="Denne streamingtjeneste understøtter ikke din aktuelle outputopløsning og/eller billedhastighed. De ændres til de(n) nærmeste kompatible værdi(er):\n\n%1\n\nFortsæt?" +Basic.Settings.Output.Warn.EnforceResolutionFPS.Resolution="Opløsning: %1" +Basic.Settings.Output.Warn.EnforceResolutionFPS.FPS="FPS (billeder/sekund): %1" Basic.Settings.Output.VideoBitrate="Videobit-hastighed" Basic.Settings.Output.AudioBitrate="Audiobit-hastighed" Basic.Settings.Output.Reconnect="Automatisk gentilslutning" @@ -688,15 +706,16 @@ Basic.Settings.Output.NoSpaceFileName="Generér filnavn uden mellemrum" Basic.Settings.Output.Adv.Rescale="Omskalér output" Basic.Settings.Output.Adv.AudioTrack="Lydspor" Basic.Settings.Output.Adv.Streaming="Streaming" -Basic.Settings.Output.Adv.ApplyServiceSettings="Håndhæv streamingtjenestes encoder-indstillinger" Basic.Settings.Output.Adv.Audio.Track1="Spor 1" Basic.Settings.Output.Adv.Audio.Track2="Spor 2" Basic.Settings.Output.Adv.Audio.Track3="Spor 3" Basic.Settings.Output.Adv.Audio.Track4="Spor 4" Basic.Settings.Output.Adv.Audio.Track5="Sport 5" Basic.Settings.Output.Adv.Audio.Track6="Spor 6" +Basic.Settings.Output.Adv.TwitchVodTrack="Twitch VOD-spor" Basic.Settings.Output.Adv.Recording="Optagelse" +Basic.Settings.Output.Adv.Recording.RecType="Optagelsestype" Basic.Settings.Output.Adv.Recording.Type="Type" Basic.Settings.Output.Adv.Recording.Type.Standard="Standard" Basic.Settings.Output.Adv.Recording.Type.FFmpegOutput="Tilpasset output (FFmpeg)" @@ -824,13 +843,18 @@ Basic.AdvAudio="Avancerede lydegenskaber" Basic.AdvAudio.ActiveOnly="Kun aktive kilder" Basic.AdvAudio.Name="Navn" Basic.AdvAudio.Volume="Lydstyrke" +Basic.AdvAudio.VolumeSource="Lydstyrke for '%1'" Basic.AdvAudio.Mono="Mono" +Basic.AdvAudio.MonoSource="Mono downmix for '%1'" Basic.AdvAudio.Balance="Balance" +Basic.AdvAudio.BalanceSource="Saldo for '%1'" Basic.AdvAudio.SyncOffset="Synk-forskydning" +Basic.AdvAudio.SyncOffsetSource="Synk-forskydning for '%1'" Basic.AdvAudio.Monitoring="Lydovervågning" Basic.AdvAudio.Monitoring.None="Overvågning Fra" Basic.AdvAudio.Monitoring.MonitorOnly="Kun overvågning (gør output tavs)" Basic.AdvAudio.Monitoring.Both="Overvåg og output" +Basic.AdvAudio.MonitoringSource="Lydovervågning til '%1'" Basic.AdvAudio.AudioTracks="Spor" Basic.Settings.Hotkeys="Genvejstaster" diff --git a/UI/data/locale/de-DE.ini b/UI/data/locale/de-DE.ini index 455c8b2..acb5d97 100644 --- a/UI/data/locale/de-DE.ini +++ b/UI/data/locale/de-DE.ini @@ -22,7 +22,7 @@ Settings="Einstellungen" Display="Bildschirm" Name="Name" Exit="Beenden" -Mixer="Audio‐Mixer" +Mixer="Audio-Mixer" Browse="Durchsuchen" Mono="Mono" Stereo="Stereo" @@ -47,8 +47,8 @@ Untitled="Unbenannt" New="Neu" Duplicate="Duplizieren" Enable="Aktivieren" -DisableOSXVSync="macOS V‐Sync deaktivieren" -ResetOSXVSyncOnExit="macOS V‐Sync beim Beenden zurücksetzen" +DisableOSXVSync="macOS VSync deaktivieren" +ResetOSXVSyncOnExit="macOS VSync beim Beenden zurücksetzen" HighResourceUsage="Codierung überlastet! Erwägen Sie Ihre Videoeinstellungen zu verringern oder benutzen Sie eine schnellere Encodervoreinstellung." Transition="Übergang" QuickTransitions="Schnellübergänge" @@ -96,18 +96,18 @@ OpenFile="Datei öffnen" AddValue="%1 hinzufügen" AlreadyRunning.Title="OBS wird bereits ausgeführt" -AlreadyRunning.Text="OBS wird bereits ausgeführt! Wenn dies unabsichtlich ist, beenden Sie alle vorhandenen OBS‐Instanzen, bevor Sie eine neue starten. Wenn Sie OBS so eingestellt haben, dass es sich zum Infobereich minimiert, überprüfen Sie bitte, ob es dort läuft." +AlreadyRunning.Text="OBS wird bereits ausgeführt! Wenn dies unabsichtlich ist, beenden Sie alle vorhandenen OBS-Instanzen, bevor Sie eine neue starten. Wenn Sie OBS so eingestellt haben, dass es sich zum Infobereich minimiert, überprüfen Sie bitte, ob es dort läuft." AlreadyRunning.LaunchAnyway="Trotzdem starten" ChromeOS.Title="Nicht unterstützte Plattform" -ChromeOS.Text="OBS scheint in einem ChromeOS‐Container zu laufen. Diese Plattform wird nicht unterstützt." +ChromeOS.Text="OBS scheint in einem ChromeOS-Container zu laufen. Diese Plattform wird nicht unterstützt." DockCloseWarning.Title="Dockbares Fenster schließen" -DockCloseWarning.Text="Sie haben gerade ein dockbares Fenster geschlossen. Wenn Sie es erneut anzeigen möchten, verwenden Sie das Menü „Ansicht“ → „Docks“ in der Menüleiste." +DockCloseWarning.Text="Sie haben gerade ein dockbares Fenster geschlossen. Wenn Sie es erneut anzeigen möchten, verwenden Sie das Menü Ansicht → Docks in der Menüleiste." -ExtraBrowsers="Benutzerdefinierte Browser‐Docks" +ExtraBrowsers="Benutzerdefinierte Browser-Docks" ExtraBrowsers.Info="Fügen Sie Docks hinzu, indem Sie ihnen einen Namen und eine URL geben und dann auf „Übernehmen“ oder „Schließen“ klicken, um diese zu öffnen. Sie können jederzeit Docks hinzufügen oder entfernen." -ExtraBrowsers.DockName="Dock‐Name" +ExtraBrowsers.DockName="Dock-Name" Auth.Authing.Title="Authentifizierung" Auth.Authing.Text="Authentifizierung mit %1, bitte warten …" @@ -121,11 +121,11 @@ Auth.ChannelFailure.Title="Fehler beim Laden des Kanals" Auth.ChannelFailure.Text="Fehler beim Laden der Kanalinformationen für %1\n\n%2: %3" Auth.Chat="Chat" Auth.StreamInfo="Streaminformation" -TwitchAuth.Stats="Twitch‐Statistiken" -TwitchAuth.Feed="Twitch‐Aktivitätsfeed" +TwitchAuth.Stats="Twitch-Statistiken" +TwitchAuth.Feed="Twitch-Aktivitätsfeed" TwitchAuth.TwoFactorFail.Title="Streamschlüssel konnte nicht abgefragt werden" -TwitchAuth.TwoFactorFail.Text="OBS konnte sich nicht mit Ihrem Twitch‐Konto verbinden. Bitte stellen Sie sicher, dass die Zwei‐Faktor‐Authentifizierung in Ihren Twitch‐Sicherheitseinstellungen eingerichtet ist, da diese für das Sreamen benötigt wird." -RestreamAuth.Channels="Restream‐Kanäle" +TwitchAuth.TwoFactorFail.Text="OBS konnte sich nicht mit Ihrem Twitch-Konto verbinden. Bitte stellen Sie sicher, dass die Zwei-Faktor-Authentifizierung in Ihren Twitch-Sicherheitseinstellungen eingerichtet ist, da diese für das Sreamen benötigt wird." +RestreamAuth.Channels="Restream-Kanäle" Copy.Filters="Filter kopieren" Paste.Filters="Filter einfügen" @@ -153,7 +153,7 @@ Basic.AutoConfig.VideoPage.BaseResolution.Display="Bildschirm %1 (%2 × %3)" Basic.AutoConfig.VideoPage.FPS.UseCurrent="Aktuelle verwenden (%1)" Basic.AutoConfig.VideoPage.FPS.PreferHighFPS="Entweder 60 oder 30, aber wenn möglich 60 bevorzugen" Basic.AutoConfig.VideoPage.FPS.PreferHighRes="Entweder 60 oder 30, aber hohe Auflösung bevorzugen" -Basic.AutoConfig.VideoPage.CanvasExplanation="Hinweis: Die Basis‐(Leinwand‐)Auflösung ist nicht unbedingt die gleiche Auflösung, mit der Sie streamen oder aufnehmen. Ihre tatsächliche Stream‐/Aufnahmeauflösung kann ausgehend von der Leinwandauflösung herunterskaliert werden, um die Ressourcennutzung oder die Bitratenanforderungen zu reduzieren." +Basic.AutoConfig.VideoPage.CanvasExplanation="Hinweis: Die Basis-(Leinwand-)Auflösung ist nicht unbedingt die gleiche Auflösung, mit der Sie streamen oder aufnehmen. Ihre tatsächliche Stream-/Aufnahmeauflösung kann ausgehend von der Leinwandauflösung herunterskaliert werden, um die Ressourcennutzung oder die Bitratenanforderungen zu reduzieren." Basic.AutoConfig.StreamPage="Streaminformationen" Basic.AutoConfig.StreamPage.SubTitle="Bitte geben Sie Ihre Streaminformationen ein" Basic.AutoConfig.StreamPage.ConnectAccount="Konto verbinden (empfohlen)" @@ -161,6 +161,7 @@ Basic.AutoConfig.StreamPage.DisconnectAccount="Konto trennen" Basic.AutoConfig.StreamPage.DisconnectAccount.Confirm.Title="Konto trennen?" Basic.AutoConfig.StreamPage.DisconnectAccount.Confirm.Text="Diese Änderung wird sofort wirksam. Sind Sie sicher, dass Sie Ihr Konto trennen möchten?" Basic.AutoConfig.StreamPage.GetStreamKey="Streamschlüssel erhalten" +Basic.AutoConfig.StreamPage.MoreInfo="Mehr Informationen" Basic.AutoConfig.StreamPage.UseStreamKey="Streamschlüssel verwenden" Basic.AutoConfig.StreamPage.Service="Plattform" Basic.AutoConfig.StreamPage.Service.ShowAll="Alle anzeigen …" @@ -170,7 +171,7 @@ Basic.AutoConfig.StreamPage.StreamKey="Streamschlüssel" Basic.AutoConfig.StreamPage.StreamKey.LinkToSite="(Link)" Basic.AutoConfig.StreamPage.PerformBandwidthTest="Bitrate mit Bandbreitentest schätzen (kann einige Minuten dauern)" Basic.AutoConfig.StreamPage.PreferHardwareEncoding="Hardwarecodierung bevorzugen" -Basic.AutoConfig.StreamPage.PreferHardwareEncoding.ToolTip="Hardwarecodierung beseitigt die meiste CPU‐Auslastung, kann aber mehr Bitrate erfordern, um das gleiche Maß an Qualität zu erhalten." +Basic.AutoConfig.StreamPage.PreferHardwareEncoding.ToolTip="Hardwarecodierung beseitigt die meiste CPU-Auslastung, kann aber mehr Bitrate erfordern, um das gleiche Maß an Qualität zu erhalten." Basic.AutoConfig.StreamPage.StreamWarning.Title="Streamwarnung" Basic.AutoConfig.StreamPage.StreamWarning.Text="Der Bandbreitentest streamt zufällige Videodaten ohne Ton zu Ihrem Kanal. Wenn Sie in der Lage sind, empfiehlt es sich, das Speichern von Videos vorrübergehend zu deaktivieren und den Stream privat zu schalten, bis der Test abgeschlossen ist. Fortfahren?" Basic.AutoConfig.TestPage="Endergebnisse" @@ -190,10 +191,10 @@ Basic.AutoConfig.TestPage.Result.RecordingEncoder="Aufnahmeencoder" Basic.AutoConfig.TestPage.Result.Header="Das Programm hat festgestellt, dass diese geschätzten Einstellungen für Sie am besten sind:" Basic.AutoConfig.TestPage.Result.Footer="Um den Assistenten neu zu konfigurieren und es erneut zu versuchen, klicken Sie auf „Zurück“. Um die Einstellungen selbst anzupassen, klicken Sie auf „Abbrechen“ und öffnen Sie die Einstellungen." Basic.AutoConfig.Info="Der Autokonfigurationsassistent ermittelt die besten Einstellungen basierend auf Ihren Computerspezifikationen und der Internetgeschwindigkeit." -Basic.AutoConfig.RunAnytime="Dies kann jederzeit über das Werkzeug‐Menü ausgeführt werden." +Basic.AutoConfig.RunAnytime="Es kann jederzeit über das Werkzeug-Menü ausgeführt werden." Basic.Stats="Statistiken" -Basic.Stats.CPUUsage="CPU‐Auslastung" +Basic.Stats.CPUUsage="CPU-Auslastung" Basic.Stats.HDDSpaceAvailable="Speicherplatz verfügbar" Basic.Stats.MemoryUsage="Speicherauslastung" Basic.Stats.AverageTimeToRender="Durchschnittliche Framerenderzeit" @@ -227,14 +228,14 @@ Updater.NoUpdatesAvailable.Title="Keine Updates verfügbar" Updater.NoUpdatesAvailable.Text="Zurzeit sind keine Updates verfügbar" Updater.FailedToLaunch="Konnte den Updater nicht starten" Updater.GameCaptureActive.Title="Spielaufnahme aktiv" -Updater.GameCaptureActive.Text="Die Spielaufnahmen‐Hook‐Bibliothek wird zurzeit verwendet. Bitte schließen Sie alle derzeit aufgenommenen Programme und Spiele (oder starten Sie Windows neu) und versuchen Sie es erneut." +Updater.GameCaptureActive.Text="Die Spielaufnahmen-Hook-Bibliothek wird zurzeit verwendet. Bitte schließen Sie alle derzeit aufgenommenen Programme und Spiele (oder starten Sie Windows neu) und versuchen Sie es erneut." -QuickTransitions.SwapScenes="Vorschau‐/Ausgabeszene nach Übergang tauschen" -QuickTransitions.SwapScenesTT="Vertauscht die Vorschau‐ und Ausgabeszenen nach dem Übergang (falls die ursprüngliche Ausgabeszene noch vorhanden ist).\nEventuelle Änderungen an der originalen Ausgabeszene werden nicht rückgängig gemacht." +QuickTransitions.SwapScenes="Vorschau-/Ausgabeszene nach Übergang tauschen" +QuickTransitions.SwapScenesTT="Vertauscht die Vorschau- und Ausgabeszenen nach dem Übergang (falls die ursprüngliche Ausgabeszene noch vorhanden ist).\nEventuelle Änderungen an der originalen Ausgabeszene werden nicht rückgängig gemacht." QuickTransitions.DuplicateScene="Szene duplizieren" QuickTransitions.DuplicateSceneTT="Ermöglicht das Bearbeiten von Transformationen und der Sichtbarkeit von Quellen, ohne die Ausgabe zu verändern, wenn dieselbe Szene bearbeitet wird.\nAktivieren Sie „Szene duplizieren“, um die Eigenschaften von Quellen zu bearbeiten, ohne die Ausgabe zu verändern.\nDas Ändern dieses Wertes wird die derzeitige Ausgabeszene zurücksetzen (falls sie noch existiert)." QuickTransitions.EditProperties="Quellen duplizieren" -QuickTransitions.EditPropertiesTT="Ermöglicht das Bearbeiten der Eigenschaften von Quellen, ohne die Ausgabe zu verändern, wenn dieselbe Szene bearbeitet wird.\nDies kann nur verwendet werden, wenn „Szene duplizieren“ aktiviert ist.\nBestimmte Quellen (wie Aufnahme‐ oder Medienquellen) unterstützen dies nicht und können nicht separat bearbeitet werden.\nDas Ändern dieses Wertes wird die derzeitige Ausgabeszene zurücksetzen (falls sie noch existiert).\n\nWarnung: Da Quellen dupliziert werden, könnte dies zusätzliche System‐ oder Videoressourcen verbrauchen." +QuickTransitions.EditPropertiesTT="Ermöglicht das Bearbeiten der Eigenschaften von Quellen, ohne die Ausgabe zu verändern, wenn dieselbe Szene bearbeitet wird.\nDies kann nur verwendet werden, wenn „Szene duplizieren“ aktiviert ist.\nBestimmte Quellen (wie Aufnahme- oder Medienquellen) unterstützen dies nicht und können nicht separat bearbeitet werden.\nDas Ändern dieses Wertes wird die derzeitige Ausgabeszene zurücksetzen (falls sie noch existiert).\n\nWarnung: Da Quellen dupliziert werden, könnte dies zusätzliche System- oder Videoressourcen verbrauchen." QuickTransitions.HotkeyName="Schnellübergang: %1" Basic.AddTransition="Konfigurierbaren Übergang hinzufügen" @@ -242,7 +243,7 @@ Basic.RemoveTransition="Konfigurierbaren Übergang entfernen" Basic.TransitionProperties="Übergangseigenschaften" Basic.SceneTransitions="Szenenübergänge" Basic.TransitionDuration="Dauer" -Basic.TogglePreviewProgramMode="Studio‐Modus" +Basic.TogglePreviewProgramMode="Studio-Modus" TransitionNameDlg.Text="Bitte geben Sie den Namen des Übergangs ein" TransitionNameDlg.Title="Übergangsname" @@ -278,13 +279,13 @@ ConfirmRemove.TextMultiple="Sind Sie sicher, dass Sie %1 Elemente entfernen möc Output.StartStreamFailed="Fehler beim Starten des Streams" Output.StartRecordingFailed="Fehler beim Starten der Aufnahme" Output.StartReplayFailed="Fehler beim Starten des Wiederholungspuffers" -Output.StartFailedGeneric="Start der Ausgabe fehlgeschlagen. Bitte überprüfen Sie die Logdatei für Details.\n\nHinweis: Wenn Sie die NVENC‐ oder AMD‐Encoder verwenden, stellen Sie sicher, dass Ihre Grafiktreiber aktuell sind." +Output.StartFailedGeneric="Start der Ausgabe fehlgeschlagen. Bitte überprüfen Sie die Logdatei für Details.\n\nHinweis: Wenn Sie die NVENC- oder AMD-Encoder verwenden, stellen Sie sicher, dass Ihre Grafiktreiber aktuell sind." Output.ReplayBuffer.PauseWarning.Title="Kann beim Pausieren keine Wiederholungen speichern" Output.ReplayBuffer.PauseWarning.Text="Warnung: Wiederholungen können beim Pausieren der Aufnahme nicht gespeichert werden." Output.ConnectFail.Title="Verbindung fehlgeschlagen" -Output.ConnectFail.BadPath="Der Pfad oder die Verbindungs‐URL ist ungültig. Bitte überprüfen Sie Ihre Einstellungen und stellen Sie sicher, dass diese korrekt sind." +Output.ConnectFail.BadPath="Der Pfad oder die Verbindungs-URL ist ungültig. Bitte überprüfen Sie Ihre Einstellungen und stellen Sie sicher, dass diese korrekt sind." Output.ConnectFail.ConnectFailed="Verbindung zum Server fehlgeschlagen" Output.ConnectFail.InvalidStream="Konnte nicht auf den angegebenen Kanal oder Streamschlüssel zugreifen. Bitte überprüfen Sie den eingegebenen Streamschlüssel. Wenn er richtig ist, kann es ein Problem beim Verbinden mit dem Server gegeben haben." Output.ConnectFail.Error="Ein unerwarteter Fehler ist beim Verbindungsversuch zum Server aufgetreten. Mehr Informationen finden Sie in der Logdatei." @@ -305,39 +306,39 @@ Output.BadPath.Title="Ungültiger Dateipfad" Output.BadPath.Text="Der konfigurierte Ausgabepfad ist ungültig. Bitte überprüfen Sie Ihre Einstellungen und stellen Sie sicher, dass ein gültiger Pfad angegeben wurde." LogReturnDialog="Log erfolgreich hochgeladen" -LogReturnDialog.Description="Ihre Logdatei wurde hochgeladen. Sie können die URL jetzt für Debugging‐ oder Support‐Zwecke teilen." -LogReturnDialog.Description.Crash="Ihr Absturzbericht wurde hochgeladen. Sie können die URL jetzt für Debugging‐Zwecke teilen." +LogReturnDialog.Description="Ihre Logdatei wurde hochgeladen. Sie können die URL jetzt für Debugging- oder Support-Zwecke teilen." +LogReturnDialog.Description.Crash="Ihr Absturzbericht wurde hochgeladen. Sie können die URL jetzt für Debugging-Zwecke teilen." LogReturnDialog.CopyURL="URL kopieren" LogReturnDialog.AnalyzeURL="Analysieren" LogReturnDialog.ErrorUploadingLog="Fehler beim Hochladen der Logdatei" -Remux.SourceFile="OBS‐Aufnahme" +Remux.SourceFile="OBS-Aufnahme" Remux.TargetFile="Zieldatei" Remux.Remux="Remuxen" Remux.Stop="Remuxen beenden" Remux.ClearFinished="Fertiggestellte Objekte entfernen" Remux.ClearAll="Alle Objekte entfernen" -Remux.OBSRecording="OBS‐Aufnahme" +Remux.OBSRecording="OBS-Aufnahme" Remux.FinishedTitle="Remuxen beendet" Remux.Finished="Aufnahme remuxed" Remux.FinishedError="Aufnahme remuxed, aber die Datei könnte unvollständig sein" -Remux.SelectRecording="Wählen Sie eine OBS‐Aufnahme aus" +Remux.SelectRecording="Wählen Sie eine OBS-Aufnahme aus" Remux.SelectTarget="Wählen Sie eine Zieldatei aus" Remux.FileExistsTitle="Zieldateien existieren bereits" Remux.FileExists="Die folgenden Zieldateien existieren bereits. Möchten Sie diese ersetzen?" Remux.ExitUnfinishedTitle="Remuxen in Bearbeitung" Remux.ExitUnfinished="Das Remuxen ist noch nicht abgeschlossen. Wenn Sie jetzt beenden, kann die Zieldatei unbrauchbar werden.\nSind Sie sicher, dass Sie das Remuxen abbrechen möchten?" -Remux.HelpText="Legen Sie Dateien in diesem Fenster ab, um sie zu remuxen oder wählen Sie eine leere „OBS‐Aufnahme“‐Zelle aus, um nach einer Datei zu suchen." +Remux.HelpText="Legen Sie Dateien in diesem Fenster ab, um sie zu remuxen oder wählen Sie eine leere „OBS-Aufnahme“-Zelle aus, um nach einer Datei zu suchen." UpdateAvailable="Neues Update verfügbar" UpdateAvailable.Text="Version %1.%2.%3 ist nun verfügbar. Hier klicken zum Herunterladen" -Basic.DesktopDevice1="Desktop‐Audio" -Basic.DesktopDevice2="Desktop‐Audio 2" -Basic.AuxDevice1="Mikrofon/AUX‐Audio" -Basic.AuxDevice2="Mikrofon/AUX‐Audio 2" -Basic.AuxDevice3="Mikrofon/AUX‐Audio 3" -Basic.AuxDevice4="Mikrofon/AUX‐Audio 4" +Basic.DesktopDevice1="Desktop-Audio" +Basic.DesktopDevice2="Desktop-Audio 2" +Basic.AuxDevice1="Mikrofon/AUX-Audio" +Basic.AuxDevice2="Mikrofon/AUX-Audio 2" +Basic.AuxDevice3="Mikrofon/AUX-Audio 3" +Basic.AuxDevice4="Mikrofon/AUX-Audio 4" Basic.Scene="Szene" Basic.DisplayCapture="Bildschirmaufnahme" @@ -365,8 +366,8 @@ Deinterlacing.Yadif2x="Yadif 2x" Deinterlacing.TopFieldFirst="Oberes Feld zuerst" Deinterlacing.BottomFieldFirst="Unteres Feld zuerst" -VolControl.SliderUnmuted="Lautstärkeschieberegler für „%1“: %2" -VolControl.SliderMuted="Lautstärkeschieberegler für „%1“: %2 (derzeit stummgeschaltet)" +VolControl.SliderUnmuted="Lautstärkeregler für „%1“:" +VolControl.SliderMuted="Lautstärkeregler für „%1“: (derzeit stummgeschaltet)" VolControl.Mute="„%1“ stummschalten" VolControl.Properties="Eigenschaften von „%1“" @@ -382,6 +383,7 @@ Basic.Main.RenameSceneCollection.Title="Szenensammlung umbenennen" AddProfile.Title="Profil hinzufügen" AddProfile.Text="Bitte geben Sie den Namen des Profils ein" +AddProfile.WizardCheckbox="Autokonfigurationsassistent anzeigen" RenameProfile.Title="Profil umbenennen" @@ -396,6 +398,11 @@ Basic.SourceSelect.CreateNew="Neu erstellen" Basic.SourceSelect.AddExisting="Existierende hinzufügen" Basic.SourceSelect.AddVisible="Quelle sichtbar machen" +Basic.Main.Sources.Visibility="Sichtbarkeit" +Basic.Main.Sources.VisibilityDescription="Steuert die Sichtbarkeit von „%1“ in der Leinwand" +Basic.Main.Sources.Lock="Sperren" +Basic.Main.Sources.LockDescription="Sperrt die Position und Größe von „%1“ in der Leinwand" + Basic.PropertiesWindow="Eigenschaften von „%1“" Basic.PropertiesWindow.AutoSelectFormat="%1 (automatisch ausgewählt: %2)" Basic.PropertiesWindow.SelectColor="Farbe auswählen" @@ -411,9 +418,9 @@ Basic.PropertiesWindow.AddEditableListFiles="Dateien zu „%1“ hinzufügen" Basic.PropertiesWindow.AddEditableListEntry="Eintrag zu „%1“ hinzufügen" Basic.PropertiesWindow.EditEditableListEntry="Eintrag aus „%1“ bearbeiten" -Basic.PropertiesView.FPS.Simple="Einfache FPS‐Werte" -Basic.PropertiesView.FPS.Rational="Rationale FPS‐Werte" -Basic.PropertiesView.FPS.ValidFPSRanges="Gültige FPS‐Bereiche:" +Basic.PropertiesView.FPS.Simple="Einfache FPS-Werte" +Basic.PropertiesView.FPS.Rational="Rationale FPS-Werte" +Basic.PropertiesView.FPS.ValidFPSRanges="Gültige FPS-Bereiche:" Basic.InteractionWindow="Mit „%1“ interagieren" @@ -426,7 +433,7 @@ Basic.StatusBar.DelayStoppingIn="Verzögerung (beende in %1 s)" Basic.StatusBar.DelayStartingStoppingIn="Verzögerung (beende in %1 s, starte in %2 s)" Basic.Filters="Filter" -Basic.Filters.AsyncFilters="Audio‐/Videofilter" +Basic.Filters.AsyncFilters="Audio-/Videofilter" Basic.Filters.AudioFilters="Audiofilter" Basic.Filters.EffectFilters="Effektfilter" Basic.Filters.Title="Filter für „%1“" @@ -537,10 +544,10 @@ Basic.MainMenu.Edit.AdvAudio="Erweiterte &Audioeigenschaften" Basic.MainMenu.View="Ansicht (&V)" Basic.MainMenu.View.Toolbars="Werkzeugleisten (&T)" Basic.MainMenu.View.Docks="Docks" -Basic.MainMenu.View.Docks.ResetUI="GUI zurücksetzen" -Basic.MainMenu.View.Docks.LockUI="GUI sperren" -Basic.MainMenu.View.Docks.CustomBrowserDocks="Benutzerdefinierte Browser‐Docks …" -Basic.MainMenu.View.ListboxToolbars="Schaltflächen für Szenen‐/Quellenlisten" +Basic.MainMenu.View.Docks.ResetUI="Benutzeroberfläche zurücksetzen" +Basic.MainMenu.View.Docks.LockUI="Benutzeroberfläche sperren" +Basic.MainMenu.View.Docks.CustomBrowserDocks="Benutzerdefinierte Browser-Docks …" +Basic.MainMenu.View.ListboxToolbars="Schaltflächen für Szenen-/Quellenlisten" Basic.MainMenu.View.ContextBar="Quellenwerkzeugleiste" Basic.MainMenu.View.SceneTransitions="Szenenübergänge (&C)" Basic.MainMenu.View.SourceIcons="Quellsymbole (&I)" @@ -561,7 +568,7 @@ Basic.MainMenu.Tools="Werkzeuge (&T)" Basic.MainMenu.Help="&Hilfe" Basic.MainMenu.Help.HelpPortal="Hilfe&portal" Basic.MainMenu.Help.Website="&Webseite besuchen" -Basic.MainMenu.Help.Discord="&Discord‐Server beitreten" +Basic.MainMenu.Help.Discord="&Discord-Server beitreten" Basic.MainMenu.Help.Logs="&Logdateien" Basic.MainMenu.Help.Logs.ShowLogs="Logdateien anzeigen (&S)" Basic.MainMenu.Help.Logs.UploadCurrentLog="Aktuelle Logdatei ho&chladen" @@ -608,8 +615,8 @@ Basic.Settings.General.OverflowSelectionHidden="Überlauf trotz unsichtbarer Que Basic.Settings.General.Importers="Importierung" Basic.Settings.General.AutomaticCollectionSearch="Beim Importieren bekannte Orte nach Szenensammlungen durchsuchen" Basic.Settings.General.SwitchOnDoubleClick="Übergang zu Szene bei Doppelklick" -Basic.Settings.General.StudioPortraitLayout="Porträt‐/vertikales Layout aktivieren" -Basic.Settings.General.TogglePreviewProgramLabels="Vorschau‐/Programmbeschriftung anzeigen" +Basic.Settings.General.StudioPortraitLayout="Porträt-/vertikales Layout aktivieren" +Basic.Settings.General.TogglePreviewProgramLabels="Vorschau-/Programmbeschriftung anzeigen" Basic.Settings.General.Multiview="Multiview" Basic.Settings.General.Multiview.MouseSwitch="Klicken, um zwischen Szenen zu wechseln" Basic.Settings.General.Multiview.DrawSourceNames="Szenennamen anzeigen" @@ -627,34 +634,40 @@ Basic.Settings.Stream.Custom.UseAuthentication="Authentifizierung verwenden" Basic.Settings.Stream.Custom.Username="Nutzername" Basic.Settings.Stream.Custom.Password="Passwort" Basic.Settings.Stream.BandwidthTestMode="Bandbreitentestmodus aktivieren" -Basic.Settings.Stream.TTVAddon="Twitch‐Chat‐Add‐Ons" +Basic.Settings.Stream.TTVAddon="Twitch-Chat-Add-Ons" Basic.Settings.Stream.TTVAddon.None="Keins" Basic.Settings.Stream.TTVAddon.Both="BetterTTV und FrankerFaceZ" Basic.Settings.Stream.MissingSettingAlert="Unvollständige Streameinrichtung" Basic.Settings.Stream.StreamSettingsWarning="Einstellungen öffnen" -Basic.Settings.Stream.MissingUrlAndApiKey="URL und Streamschlüssel fehlen.\n\nÖffnen Sie die Einstellungen, um die URL und den Streamschlüssel im Stream‐Tab einzugeben." -Basic.Settings.Stream.MissingUrl="Stream‐URL fehlt.\n\nÖffnen Sie die Einstellungen, um die URL im Stream‐Tab einzugeben." -Basic.Settings.Stream.MissingStreamKey="Streamschlüssel fehlt.\n\nÖffnen Sie die Einstellungen, um den Streamschlüssel im Stream‐Tab einzugeben." +Basic.Settings.Stream.MissingUrlAndApiKey="URL und Streamschlüssel fehlen.\n\nÖffnen Sie die Einstellungen, um die URL und den Streamschlüssel im Stream-Tab einzugeben." +Basic.Settings.Stream.MissingUrl="Stream-URL fehlt.\n\nÖffnen Sie die Einstellungen, um die URL im Stream-Tab einzugeben." +Basic.Settings.Stream.MissingStreamKey="Streamschlüssel fehlt.\n\nÖffnen Sie die Einstellungen, um den Streamschlüssel im Stream-Tab einzugeben." +Basic.Settings.Stream.IgnoreRecommended="Empfehlungen für Einstellungen der Streamingplattform ignorieren" +Basic.Settings.Stream.IgnoreRecommended.Warn.Title="Empfohlene Einstellungen überschreiben" +Basic.Settings.Stream.IgnoreRecommended.Warn.Text="Warnung: Das Ignorieren von Limitierungen einer Plattform kann zu einer verschlechterten Streamqualität führen oder Sie komplett am Streamen hindern.\n\nFortfahren?" +Basic.Settings.Stream.Recommended.MaxVideoBitrate="Maximale Videobitrate: %1 kbps" +Basic.Settings.Stream.Recommended.MaxAudioBitrate="Maximale Audiobitrate: %1 kbps" +Basic.Settings.Stream.Recommended.MaxResolution="Maximale Auflösung: %1" +Basic.Settings.Stream.Recommended.MaxFPS="Maximale FPS: %1" Basic.Settings.Output="Ausgabe" Basic.Settings.Output.Format="Aufnahmeformat" Basic.Settings.Output.Encoder="Encoder" Basic.Settings.Output.SelectDirectory="Wählen Sie den Aufnahmeordner aus" Basic.Settings.Output.SelectFile="Wählen Sie ein Aufnahmedatei aus" -Basic.Settings.Output.EnforceBitrate="Bitratenlimit des Streamingdienstes erzwingen" Basic.Settings.Output.DynamicBitrate="Bitrate dynamisch verändern, um Überlastung zu kontrollieren" Basic.Settings.Output.DynamicBitrate.Beta="Bitrate dynamisch verändern, um Überlastung zu kontrollieren (Beta)" Basic.Settings.Output.DynamicBitrate.TT="Anstatt Frames wegfallen zu lassen, um Überlastung zu verringern, wird die Bitrate dynamisch verändert.\n\nBeachten Sie, dass dies die Verzögerung zu den Zuschauern bei erheblich unerwartet hoher Überlastung erhöhen kann.\nWenn die Bitrate fällt, kann der Wiederherstellungsvorgang ein paar Minuten dauern.\n\nDerzeit nur für RTMP unterstützt." Basic.Settings.Output.Mode="Ausgabemodus" Basic.Settings.Output.Mode.Simple="Einfach" Basic.Settings.Output.Mode.Adv="Erweitert" -Basic.Settings.Output.Mode.FFmpeg="FFmpeg‐Ausgabe" +Basic.Settings.Output.Mode.FFmpeg="FFmpeg-Ausgabe" Basic.Settings.Output.UseReplayBuffer="Wiederholungspuffer aktivieren" Basic.Settings.Output.ReplayBuffer.SecondsMax="Maximale Wiederholungszeit" -Basic.Settings.Output.ReplayBuffer.MegabytesMax="Maximale RAM‐Nutzung in MB" -Basic.Settings.Output.ReplayBuffer.Estimate="Geschätzte RAM‐Nutzung: %1 MB" -Basic.Settings.Output.ReplayBuffer.EstimateUnknown="RAM‐Nutzung kann nicht geschätzt werden. Stellen Sie diese bitte ein." -Basic.Settings.Output.ReplayBuffer.Prefix="Wiederholungspuffer‐Dateinamen‐Präfix" +Basic.Settings.Output.ReplayBuffer.MegabytesMax="Maximale RAM-Nutzung in MB" +Basic.Settings.Output.ReplayBuffer.Estimate="Geschätzte RAM-Nutzung: %1 MB" +Basic.Settings.Output.ReplayBuffer.EstimateUnknown="RAM-Nutzung kann nicht geschätzt werden. Stellen Sie diese bitte ein." +Basic.Settings.Output.ReplayBuffer.Prefix="Wiederholungspuffer-Dateinamen-Präfix" Basic.Settings.Output.ReplayBuffer.Suffix="Suffix" Basic.Settings.Output.Simple.SavePath="Aufnahmepfad" Basic.Settings.Output.Simple.RecordingQuality="Aufnahmequalität" @@ -662,10 +675,10 @@ Basic.Settings.Output.Simple.RecordingQuality.Stream="Gleich wie Stream" Basic.Settings.Output.Simple.RecordingQuality.Small="Hohe Qualität; mittelgroße Dateien" Basic.Settings.Output.Simple.RecordingQuality.HQ="Ununterscheidbare Qualität; große Dateien" Basic.Settings.Output.Simple.RecordingQuality.Lossless="Verlustfreie Qualität; enorm große Dateien" -Basic.Settings.Output.Simple.Warn.VideoBitrate="Warnung: Die Videobitrate beim Streamen wird auf %1 festgelegt, was der Obergrenze des aktuellen Streamingdienstes entspricht. Falls Sie sicher sind, dass Sie %1 überschreiten wollen, deaktivieren Sie „Bitratenlimit des Streamingdienstes erzwingen“ in den erweiterten Encodereinstellungen." -Basic.Settings.Output.Simple.Warn.AudioBitrate="Warnung: Die Audiobitrate beim Streamen wird auf %1 festgelegt, was der Obergrenze des aktuellen Streamingdienstes entspricht. Falls Sie sicher sind, dass Sie %1 überschreiten wollen, deaktivieren Sie „Bitratenlimit des Streamingdienstes erzwingen“ in den erweiterten Encodereinstellungen." +Basic.Settings.Output.Simple.Warn.VideoBitrate="Warnung: Die Streamvideobitrate wird auf %1 gesetzt, was der oberen Grenze der aktuellen Streamingplattform entspricht." +Basic.Settings.Output.Simple.Warn.AudioBitrate="Warnung: Die Streamaudiobitrate wird auf %1 gesetzt, was der oberen Grenze der aktuellen Streamingplattform entspricht." Basic.Settings.Output.Simple.Warn.CannotPause="Warnung: Aufnahmen können nicht pausiert werden, wenn die Aufnahmequalität „Gleich wie Stream“ ist." -Basic.Settings.Output.Simple.Warn.Encoder="Warnung: Mit einem Softwareencoder in einer anderen Qualität als der des Streams aufzunehmen erfordert zusätzliche CPU‐Auslastung, wenn Sie gleichzeitig streamen und aufnehmen." +Basic.Settings.Output.Simple.Warn.Encoder="Warnung: Mit einem Softwareencoder in einer anderen Qualität als der des Streams aufzunehmen erfordert zusätzliche CPU-Auslastung, wenn Sie gleichzeitig streamen und aufnehmen." Basic.Settings.Output.Simple.Warn.Lossless="Warnung: Verlustfreie Qualität erzeugt enorm große Dateien! Bei dieser Einstellung kann bei hohen Auflösungen und Frameraten mehr als 7 GB Speicherplatz pro Minute in Anspruch genommen werden. Sie ist für lange Aufnahmen daher nicht empfohlen, es sei denn, Sie haben eine sehr große Menge an Speicherplatz zur Verfügung." Basic.Settings.Output.Simple.Warn.Lossless.Msg="Sind Sie sicher, dass Sie verlustfreie Qualität verwenden möchten?" Basic.Settings.Output.Simple.Warn.Lossless.Title="Warnung zur verlustfreien Qualität" @@ -673,7 +686,12 @@ 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‐Auslastungsvoreinstellung; erhöht die Dateigröße)" +Basic.Settings.Output.Simple.Encoder.SoftwareLowCPU="Software (x264 niedrige CPU-Auslastungsvoreinstellung; erhöht die Dateigröße)" +Basic.Settings.Output.Simple.TwitchVodTrack="Twitch-VOD-Spur (verwendet Spur 2)" +Basic.Settings.Output.Warn.EnforceResolutionFPS.Title="Inkompatible Auflösung/Framerate" +Basic.Settings.Output.Warn.EnforceResolutionFPS.Msg="Diese Streamingplattform unterstützt Ihre aktuelle Ausgabeauflösung und/oder Framerate nicht. Die Werte werden auf den nächstmöglichen kompatiblen Wert geändert:\n\n%1\n\nMöchten Sie fortfahren?" +Basic.Settings.Output.Warn.EnforceResolutionFPS.Resolution="Auflösung: %1" +Basic.Settings.Output.Warn.EnforceResolutionFPS.FPS="FPS: %1" Basic.Settings.Output.VideoBitrate="Videobitrate" Basic.Settings.Output.AudioBitrate="Audiobitrate" Basic.Settings.Output.Reconnect="Automatisch wiederverbinden" @@ -688,40 +706,41 @@ Basic.Settings.Output.NoSpaceFileName="Dateinamen ohne Leerzeichen generieren" Basic.Settings.Output.Adv.Rescale="Ausgabe umskalieren" Basic.Settings.Output.Adv.AudioTrack="Audiospur" Basic.Settings.Output.Adv.Streaming="Streaming" -Basic.Settings.Output.Adv.ApplyServiceSettings="Encodereinstellungen des Streamingdienstes erzwingen" Basic.Settings.Output.Adv.Audio.Track1="Spur 1" Basic.Settings.Output.Adv.Audio.Track2="Spur 2" Basic.Settings.Output.Adv.Audio.Track3="Spur 3" Basic.Settings.Output.Adv.Audio.Track4="Spur 4" Basic.Settings.Output.Adv.Audio.Track5="Spur 5" Basic.Settings.Output.Adv.Audio.Track6="Spur 6" +Basic.Settings.Output.Adv.TwitchVodTrack="Twitch-VOD-Spur" Basic.Settings.Output.Adv.Recording="Aufnahme" +Basic.Settings.Output.Adv.Recording.RecType="Aufnahmetyp" Basic.Settings.Output.Adv.Recording.Type="Art" Basic.Settings.Output.Adv.Recording.Type.Standard="Normal" Basic.Settings.Output.Adv.Recording.Type.FFmpegOutput="Benutzerdefinierte Ausgabe (FFmpeg)" Basic.Settings.Output.Adv.Recording.UseStreamEncoder="(Streamencoder verwenden)" Basic.Settings.Output.Adv.Recording.Filename="Dateinamenformatierung" Basic.Settings.Output.Adv.Recording.OverwriteIfExists="Überschreiben, wenn Datei vorhanden" -Basic.Settings.Output.Adv.FFmpeg.Type="FFmpeg‐Ausgabetyp" +Basic.Settings.Output.Adv.FFmpeg.Type="FFmpeg-Ausgabetyp" Basic.Settings.Output.Adv.FFmpeg.Type.URL="Ausgabe zu URL" Basic.Settings.Output.Adv.FFmpeg.Type.RecordToFile="Ausgabe in Datei" Basic.Settings.Output.Adv.FFmpeg.SaveFilter.Common="Häufige Aufnahmeformate" Basic.Settings.Output.Adv.FFmpeg.SaveFilter.All="Alle Dateien" Basic.Settings.Output.Adv.FFmpeg.SavePathURL="Dateipfad oder URL" -Basic.Settings.Output.Adv.FFmpeg.Format="Container‐Format" +Basic.Settings.Output.Adv.FFmpeg.Format="Container-Format" Basic.Settings.Output.Adv.FFmpeg.FormatAudio="Audio" Basic.Settings.Output.Adv.FFmpeg.FormatVideo="Video" Basic.Settings.Output.Adv.FFmpeg.FormatDefault="Standardformat" -Basic.Settings.Output.Adv.FFmpeg.FormatDesc="Container‐Formatbeschreibung" -Basic.Settings.Output.Adv.FFmpeg.FormatDescDef="Audio‐/Videocodec wird aus Dateipfad oder URL gebildet" +Basic.Settings.Output.Adv.FFmpeg.FormatDesc="Container-Formatbeschreibung" +Basic.Settings.Output.Adv.FFmpeg.FormatDescDef="Audio-/Videocodec wird aus Dateipfad oder URL gebildet" Basic.Settings.Output.Adv.FFmpeg.AVEncoderDefault="Standardencoder" Basic.Settings.Output.Adv.FFmpeg.AVEncoderDisable="Encoder deaktivieren" Basic.Settings.Output.Adv.FFmpeg.VEncoder="Videoencoder" Basic.Settings.Output.Adv.FFmpeg.VEncoderSettings="Videoencodereinstellungen (falls angegeben)" Basic.Settings.Output.Adv.FFmpeg.AEncoder="Audioencoder" Basic.Settings.Output.Adv.FFmpeg.AEncoderSettings="Audioencodereinstellungen (falls angegeben)" -Basic.Settings.Output.Adv.FFmpeg.MuxerSettings="Muxer‐Einstellungen (falls angegeben)" +Basic.Settings.Output.Adv.FFmpeg.MuxerSettings="Muxer-Einstellungen (falls angegeben)" Basic.Settings.Output.Adv.FFmpeg.GOPSize="Keyframeintervall (Frames)" Basic.Settings.Output.Adv.FFmpeg.IgnoreCodecCompat="Alle Codecs anzeigen (auch wenn möglicherweise inkompatibel)" @@ -734,18 +753,18 @@ Screenshot.Source="Screenshot erstellen (Quelle)" FilenameFormatting.completer="%DD-%MM-%CCYY %hh-%mm-%ss\n%DD-%MM-%YY %hh-%mm-%ss\n%d-%m-%Y %H-%M-%S\n%d-%m-%y %H-%M-%S\n%a %d-%m-%Y %H-%M-%S\n%A %d-%m-%Y %H-%M-%S\n%d-%b-%Y %H-%M-%S\n%d-%B-%Y %H-%M-%S\n%FPS\n%CRES\n%ORES\n%VF" -FilenameFormatting.TT="%CCYY Jahr; vier Ziffern\n%YY Jahr; letzte zwei Ziffern (00–99)\n%MM Monat als Dezimalzahl (01–12)\n%DD Tag des Monats mit Nullen aufgefüllt (01–31)\n%hh Stunden im 24‐Stunden‐Format (00–23)\n%mm Minute (00–59)\n%ss Sekunde (00–61)\n%% ein %‐Zeichen\n%a abgekürzter Wochentagsname (Englisch)\n%A voller Wochentagsname (Englisch)\n%b abgekürzer Monatsname (Englisch)\n%B voller Monatsname (Englisch)\n%d Tag des Monats mit Nullen aufgefüllt (01–31)\n%H Stunden im 24‐Stunden‐Format (00–23)\n%I Stunden im 12‐Stunden‐Format (01–12)\n%m Monat als Dezimalzahl (01–12)\n%M Minute (00–59)\n%p vormittags‐ oder nachmittags‐Angabe\n%S Sekunde (00–61)\n%y Jahr; letzte zwei Ziffern (00–99)\n%Y Jahr\n%z ISO‐8601‐Verschiebung von UTC oder Zeitzone\n%Z Zeitzonenname oder Abkürzung\n%FPS Frames pro Sekunde\n%CRES Basis‐(Leinwand‐)Auflösung\n%ORES (skalierte) Ausgabeauflösung\n%VF Videoformat" +FilenameFormatting.TT="%CCYY Jahr; vier Ziffern\n%YY Jahr; letzte zwei Ziffern (00–99)\n%MM Monat als Dezimalzahl (01–12)\n%DD Tag des Monats mit Nullen aufgefüllt (01–31)\n%hh Stunden im 24-Stunden-Format (00–23)\n%mm Minute (00–59)\n%ss Sekunde (00–61)\n%% ein %-Zeichen\n%a abgekürzter Wochentagsname (Englisch)\n%A voller Wochentagsname (Englisch)\n%b abgekürzer Monatsname (Englisch)\n%B voller Monatsname (Englisch)\n%d Tag des Monats mit Nullen aufgefüllt (01–31)\n%H Stunden im 24-Stunden-Format (00–23)\n%I Stunden im 12-Stunden-Format (01–12)\n%m Monat als Dezimalzahl (01–12)\n%M Minute (00–59)\n%p vormittags- oder nachmittags-Angabe\n%S Sekunde (00–61)\n%y Jahr; letzte zwei Ziffern (00–99)\n%Y Jahr\n%z ISO-8601-Verschiebung von UTC oder Zeitzone\n%Z Zeitzonenname oder Abkürzung\n%FPS Frames pro Sekunde\n%CRES Basis-(Leinwand-)Auflösung\n%ORES (skalierte) Ausgabeauflösung\n%VF Videoformat" Basic.Settings.Video="Video" Basic.Settings.Video.Adapter="Grafikkarte" -Basic.Settings.Video.BaseResolution="Basis‐(Leinwand‐)Auflösung" +Basic.Settings.Video.BaseResolution="Basis-(Leinwand-)Auflösung" Basic.Settings.Video.ScaledResolution="(Skalierte) Ausgabeauflösung" Basic.Settings.Video.DownscaleFilter="Skalierungsfilter" Basic.Settings.Video.DisableAeroWindows="Aero deaktivieren (nur Windows)" Basic.Settings.Video.FPS="FPS" -Basic.Settings.Video.FPSCommon="Übliche FPS‐Werte" -Basic.Settings.Video.FPSInteger="Ganzzahl‐FPS‐Wert" -Basic.Settings.Video.FPSFraction="Bruch‐FPS‐Wert" +Basic.Settings.Video.FPSCommon="Übliche FPS-Werte" +Basic.Settings.Video.FPSInteger="Ganzzahl-FPS-Wert" +Basic.Settings.Video.FPSFraction="Bruch-FPS-Wert" Basic.Settings.Video.Numerator="Zähler" Basic.Settings.Video.Denominator="Nenner" Basic.Settings.Video.Renderer="Renderer" @@ -768,22 +787,22 @@ Basic.Settings.Audio.MeterDecayRate.Medium="Mittel (Type I PPM)" Basic.Settings.Audio.MeterDecayRate.Slow="Langsam (Type II PPM)" Basic.Settings.Audio.PeakMeterType="Spitzenmessertyp" Basic.Settings.Audio.PeakMeterType.SamplePeak="Sample Peak" -Basic.Settings.Audio.PeakMeterType.TruePeak="True Peak (höhere CPU‐Auslastung)" -Basic.Settings.Audio.MultiChannelWarning.Enabled="WARNUNG: Surround‐Sound‐Audio ist aktiviert." -Basic.Settings.Audio.MultichannelWarning="Überprüfen Sie beim Streamen, ob Ihr Streamingdienst sowohl die Einspeisung von Surround‐Sound als auch die Surround‐Sound‐Wiedergabe unterstützt. Facebook 360 Live ist ein Beispiel, bei dem Surround‐Sound voll unterstützt wird. Obwohl Facebook Live und YouTube Live beide die Surround‐Einspeisung akzeptieren, wird Facebook Live auf Stereo heruntergemischt und YouTube Live spielt nur zwei Kanäle ab.\n\nOBS‐Audiofilter sind mit Surround‐Sound kompatibel, die VST‐Pluginunterstützung ist aber nicht garantiert." -Basic.Settings.Audio.MultichannelWarning.Title="Surround‐Sound‐Audio aktivieren?" -Basic.Settings.Audio.MultichannelWarning.Confirm="Sind Sie sicher, dass Sie Surround‐Sound‐Audio wirklich aktivieren möchten?" +Basic.Settings.Audio.PeakMeterType.TruePeak="True Peak (höhere CPU-Auslastung)" +Basic.Settings.Audio.MultiChannelWarning.Enabled="WARNUNG: Surround-Sound-Audio ist aktiviert." +Basic.Settings.Audio.MultichannelWarning="Überprüfen Sie beim Streamen, ob Ihre Streamingplattform sowohl die Einspeisung von Surround-Sound als auch die Surround-Sound-Wiedergabe unterstützt. Facebook 360 Live ist ein Beispiel, bei dem Surround-Sound voll unterstützt wird. Obwohl Facebook Live und YouTube Live beide die Surround-Einspeisung akzeptieren, wird Facebook Live auf Stereo heruntergemischt und YouTube Live spielt nur zwei Kanäle ab.\n\nOBS-Audiofilter sind mit Surround-Sound kompatibel, die VST-Pluginunterstützung ist aber nicht garantiert." +Basic.Settings.Audio.MultichannelWarning.Title="Surround-Sound-Audio aktivieren?" +Basic.Settings.Audio.MultichannelWarning.Confirm="Sind Sie sicher, dass Sie Surround-Sound-Audio wirklich aktivieren möchten?" Basic.Settings.Audio.Devices="Globale Audiogeräte" -Basic.Settings.Audio.DesktopDevice="Desktop‐Audio" -Basic.Settings.Audio.DesktopDevice2="Desktop‐Audio 2" -Basic.Settings.Audio.AuxDevice="Mikrofon/AUX‐Audio" -Basic.Settings.Audio.AuxDevice2="Mikrofon/AUX‐Audio 2" -Basic.Settings.Audio.AuxDevice3="Mikrofon/AUX‐Audio 3" -Basic.Settings.Audio.AuxDevice4="Mikrofon/AUX‐Audio 4" -Basic.Settings.Audio.EnablePushToMute="Push‐To‐Mute aktivieren" -Basic.Settings.Audio.PushToMuteDelay="Push‐To‐Mute‐Verzögerung" -Basic.Settings.Audio.EnablePushToTalk="Push‐To‐Talk aktivieren" -Basic.Settings.Audio.PushToTalkDelay="Push‐To‐Talk‐Verzögerung" +Basic.Settings.Audio.DesktopDevice="Desktop-Audio" +Basic.Settings.Audio.DesktopDevice2="Desktop-Audio 2" +Basic.Settings.Audio.AuxDevice="Mikrofon/AUX-Audio" +Basic.Settings.Audio.AuxDevice2="Mikrofon/AUX-Audio 2" +Basic.Settings.Audio.AuxDevice3="Mikrofon/AUX-Audio 3" +Basic.Settings.Audio.AuxDevice4="Mikrofon/AUX-Audio 4" +Basic.Settings.Audio.EnablePushToMute="Push-To-Mute aktivieren" +Basic.Settings.Audio.PushToMuteDelay="Push-To-Mute-Verzögerung" +Basic.Settings.Audio.EnablePushToTalk="Push-To-Talk aktivieren" +Basic.Settings.Audio.PushToTalkDelay="Push-To-Talk-Verzögerung" Basic.Settings.Audio.UnknownAudioDevice="[Gerät nicht angeschlossen oder nicht verfügbar]" Basic.Settings.Audio.Disabled="Deaktiviert" @@ -794,25 +813,25 @@ Basic.Settings.Advanced.General.ProcessPriority.AboveNormal="Höher als normal" Basic.Settings.Advanced.General.ProcessPriority.Normal="Normal" Basic.Settings.Advanced.General.ProcessPriority.BelowNormal="Niedriger als normal" Basic.Settings.Advanced.General.ProcessPriority.Idle="Niedrig" -Basic.Settings.Advanced.FormatWarning="Warnung: Andere Farbformate als NV12 sind in erster Linie für die Aufnahme bestimmt und sind für Streaming nicht zu empfehlen. Die erforderliche Farbformatkonvertierung kann eine erhöhte CPU‐Auslastung hervorrufen." +Basic.Settings.Advanced.FormatWarning="Warnung: Andere Farbformate als NV12 sind in erster Linie für die Aufnahme bestimmt und sind für Streaming nicht zu empfehlen. Die erforderliche Farbformatkonvertierung kann eine erhöhte CPU-Auslastung hervorrufen." Basic.Settings.Advanced.Audio.BufferingTime="Audiopufferungszeit" Basic.Settings.Advanced.Video.ColorFormat="Farbformat" Basic.Settings.Advanced.Video.ColorSpace="Farbraum" Basic.Settings.Advanced.Video.ColorRange="Farbbereich" Basic.Settings.Advanced.Video.ColorRange.Partial="Begrenzt" Basic.Settings.Advanced.Video.ColorRange.Full="Voll" -Basic.Settings.Advanced.Audio.MonitoringDevice="Monitoring‐Gerät" +Basic.Settings.Advanced.Audio.MonitoringDevice="Monitoring-Gerät" Basic.Settings.Advanced.Audio.MonitoringDevice.Default="Standard" -Basic.Settings.Advanced.Audio.DisableAudioDucking="Windows‐Audioducking deaktivieren" +Basic.Settings.Advanced.Audio.DisableAudioDucking="Windows-Audioducking deaktivieren" Basic.Settings.Advanced.StreamDelay="Streamverzögerung" Basic.Settings.Advanced.StreamDelay.Duration="Dauer" -Basic.Settings.Advanced.StreamDelay.Preserve="Lückenloses Wiederverbinden (erhöht Verzögerung, um Videoverlust zu vermeiden)" +Basic.Settings.Advanced.StreamDelay.Preserve="Lückenloses Wiederverbinden (erhöht Verzögerung, um Videoverluste zu vermeiden)" Basic.Settings.Advanced.StreamDelay.MemoryUsage="Geschätzte Speichernutzung: %1 MB" Basic.Settings.Advanced.Network="Netzwerk" Basic.Settings.Advanced.Network.BindToIP="Interface" Basic.Settings.Advanced.Network.EnableNewSocketLoop="Netzwerkoptimierung aktivieren" Basic.Settings.Advanced.Network.EnableLowLatencyMode="TCP Pacing aktivieren" -Basic.Settings.Advanced.Network.TCPPacing.Tooltip="Versucht, die RTMP‐Ausgabe für andere latenzempfindliche Anwendungen im Netzwerk durch Regulierung der Übertragungsrate zu erleichtern.\nDies kann zur Erhöhung des Risikos für ausgelassene Frames bei instabilen Verbindungen führen." +Basic.Settings.Advanced.Network.TCPPacing.Tooltip="Versucht, die RTMP-Ausgabe für andere latenzempfindliche Anwendungen im Netzwerk durch Regulierung der Übertragungsrate zu erleichtern.\nDies kann zur Erhöhung des Risikos für ausgelassene Frames bei instabilen Verbindungen führen." Basic.Settings.Advanced.Hotkeys.HotkeyFocusBehavior="Hotkeyfokusverhalten" Basic.Settings.Advanced.Hotkeys.NeverDisableHotkeys="Hotkeys nie deaktivieren" Basic.Settings.Advanced.Hotkeys.DisableHotkeysInFocus="Hotkeys deaktivieren, wenn Hauptfenster im Fokus" @@ -824,13 +843,18 @@ Basic.AdvAudio="Erweiterte Audioeigenschaften" Basic.AdvAudio.ActiveOnly="Nur aktive Quellen" Basic.AdvAudio.Name="Name" Basic.AdvAudio.Volume="Lautstärke" +Basic.AdvAudio.VolumeSource="Lautstärke für „%1“" Basic.AdvAudio.Mono="Mono" +Basic.AdvAudio.MonoSource="Mono-Downmix für „%1“" Basic.AdvAudio.Balance="Balance" +Basic.AdvAudio.BalanceSource="Balance für „%1“" Basic.AdvAudio.SyncOffset="Synchronisationsausgleich" -Basic.AdvAudio.Monitoring="Audio‐Monitoring" +Basic.AdvAudio.SyncOffsetSource="Synchronisationsausgleich für „%1“" +Basic.AdvAudio.Monitoring="Audio-Monitoring" Basic.AdvAudio.Monitoring.None="Monitor aus" Basic.AdvAudio.Monitoring.MonitorOnly="Nur Monitor (Ausgabe stummschalten)" Basic.AdvAudio.Monitoring.Both="Monitor und Ausgabe" +Basic.AdvAudio.MonitoringSource="Audio-Monitoring für „%1“" Basic.AdvAudio.AudioTracks="Spuren" Basic.Settings.Hotkeys="Hotkeys" @@ -850,8 +874,8 @@ Hotkeys.Home="Pos1" Hotkeys.End="Ende" Hotkeys.PageUp="Bild nach oben" Hotkeys.PageDown="Bild nach unten" -Hotkeys.NumLock="Num‐Taste" -Hotkeys.ScrollLock="Rollen‐Taste" +Hotkeys.NumLock="Num-Taste" +Hotkeys.ScrollLock="Rollen-Taste" Hotkeys.CapsLock="Feststelltaste" Hotkeys.Backspace="Rücktaste" Hotkeys.Tab="Tabulator" @@ -883,14 +907,14 @@ Hotkeys.Escape="Esc" Mute="Stummschalten" Unmute="Stummschaltung aufheben" -Push-to-mute="Push‐To‐Mute" -Push-to-talk="Push‐To‐Talk" +Push-to-mute="Push-To-Mute" +Push-to-talk="Push-To-Talk" SceneItemShow="„%1“ anzeigen" SceneItemHide="„%1“ verstecken" OutputWarnings.NoTracksSelected="Sie müssen mindestens eine Spur auswählen" -OutputWarnings.MP4Recording="Warnung: Aufnahmen, die in MP4/MOV gespeichert werden, sind nicht wiederherstellbar, wenn die Datei nicht abgeschlossen werden konnte (z. B. als Folge von BSODs, Stromausfällen, etc.). Wenn Sie mehrere Audiospuren aufnehmen möchten, sollten Sie MKV verwenden und die Aufnahme zu MP4/MOV remuxen, nachdem sie fertig ist. („Datei“ → „Aufnahmen remuxen“)" +OutputWarnings.MP4Recording="Warnung: Aufnahmen, die in MP4/MOV gespeichert werden, sind nicht wiederherstellbar, wenn die Datei nicht abgeschlossen werden konnte (z. B. als Folge von BSODs, Stromausfällen, etc.). Wenn Sie mehrere Audiospuren aufnehmen möchten, sollten Sie MKV verwenden und die Aufnahme zu MP4/MOV remuxen, nachdem sie fertig ist. (Datei → Aufnahmen remuxen)" OutputWarnings.CannotPause="Warnung: Aufnahmen können nicht pausiert werden, wenn der Aufnahmeencoder auf „(Streamencoder verwenden)“ gesetzt ist" FinalScene.Title="Szene entfernen" @@ -898,8 +922,8 @@ FinalScene.Text="Es muss mindestens eine Szene vorhanden sein." NoSources.Title="Keine Quellen" NoSources.Text="Offenbar haben Sie noch keine Videoquellen hinzugefügt, sodass nur ein leerer Bildschirm ausgegeben wird. Sind Sie sicher, dass Sie das wollen?" -NoSources.Text.AddSource="Sie können jederzeit Quellen hinzufügen, indem Sie auf das +‐Symbol unter dem Quellenfeld im Hauptfenster klicken." -NoSources.Label="Sie haben bis jetzt keine Quellen hinzugefügt.\nKlicken Sie auf das +‐Symbol oder\nrechtsklicken Sie hier, um welche hinzuzufügen." +NoSources.Text.AddSource="Sie können jederzeit Quellen hinzufügen, indem Sie auf das +-Symbol unter dem Quellenfeld im Hauptfenster klicken." +NoSources.Label="Sie haben bis jetzt keine Quellen hinzugefügt.\nKlicken Sie auf das +-Symbol oder\nrechtsklicken Sie hier, um welche hinzuzufügen." ChangeBG="Farbe auswählen" CustomColor="Benutzerdefinierte Farbe" @@ -907,19 +931,19 @@ CustomColor="Benutzerdefinierte Farbe" BrowserSource.EnableHardwareAcceleration="Browserhardwarebeschleunigung aktivieren" About="Über OBS Studio" -About.Info="OBS Studio ist eine freie und Open‐Source‐Videoaufnahme‐ und Livestreaming‐Software." +About.Info="OBS Studio ist eine freie und Open-Source-Videoaufnahme- und Livestreaming-Software." About.Donate="Leisten Sie einen Beitrag" About.GetInvolved="Wirken Sie mit" About.Authors="Autoren" About.License="Lizenzvereinbarung" -About.Contribute="Unterstützen Sie das OBS‐Projekt" +About.Contribute="Unterstützen Sie das OBS-Projekt" AddUrl.Title="Quelle per URL hinzufügen" AddUrl.Text="Sie haben eine URL in OBS gezogen. Dies wird automatisch den Link als Quelle hinzufügen. Fortfahren?" AddUrl.Text.Url="URL: %1" ResizeOutputSizeOfSource="Ausgabeauflösung anpassen (Quellgröße)" -ResizeOutputSizeOfSource.Text="Die Basis‐ und Ausgabeauflösung wird auf die Größe der aktuellen Quelle geändert." +ResizeOutputSizeOfSource.Text="Die Basis- und Ausgabeauflösung wird auf die Größe der aktuellen Quelle geändert." ResizeOutputSizeOfSource.Continue="Möchten Sie fortfahren?" PreviewTransition="Übergangsvorschau" @@ -931,7 +955,7 @@ Importer.HelpText="Fügen Sie Dateien zu diesem Fenster hinzu, um Sammlungen von Importer.Path="Sammlungspfad" Importer.Program="Erkannte Anwendung" Importer.AutomaticCollectionPrompt="Automatisch nach Szenensammlungen suchen" -Importer.AutomaticCollectionText="OBS kann automatisch importierbare Szenensammlungen von Drittanbieter‐Programmen finden. Möchten Sie, dass OBS automatisch nach Sammlungen für Sie sucht?\n\nSie können diese Einstellung später unter „Einstellungen“ → „Allgemein“ → „Importierung“ ändern." +Importer.AutomaticCollectionText="OBS kann automatisch importierbare Szenensammlungen von Drittanbieter-Programmen finden. Möchten Sie, dass OBS automatisch nach Sammlungen für Sie sucht?\n\nSie können diese Einstellung später unter Einstellungen → Allgemein → Importierung ändern." Restart="Neustart" diff --git a/UI/data/locale/el-GR.ini b/UI/data/locale/el-GR.ini index 6370c53..ce1a6d7 100644 --- a/UI/data/locale/el-GR.ini +++ b/UI/data/locale/el-GR.ini @@ -93,6 +93,7 @@ LockVolume="Κλείδωμα Έντασης" LogViewer="Προβολή καταγραφών" ShowOnStartup="Εμφάνιση κατά την εκκίνηση" OpenFile="Άνοιγμα αρχείου" +AddValue="Προσθήκη %1" AlreadyRunning.Title="Το OBS εκτελείται ήδη" AlreadyRunning.Text="Το OBS εκτελείται ήδη! Εκτός αν αυτός ήταν ο σκοπός σας, παρακαλούμε τερματίστε τις τρέχουσες διεργασίες OBS πριν προσπαθήσετε να εκκινήσετε μια καινούρια. Εάν έχετε ρυθμίσει το OBS να ελαχιστοποιείται στην γραμμή εργαλείων, παρακαλούμε να ελέγξετε αν τρέχει ήδη εκεί." @@ -102,6 +103,7 @@ ChromeOS.Title="Μη υποστηριγμένη πλατφόρμα" ChromeOS.Text="Φαίνεται πως το OBS τρέχει σε ένα ChromeOS container. Η πλατφόρμα αυτή δεν υποστηρίζεται" DockCloseWarning.Title="Κλείσιμο \"δεμένου\" παραθύρου" +DockCloseWarning.Text="Μόλις κλείσατε ένα στοιχιζόμενο παράθυρο. Αν θέλετε να το ξαναεμφανίσετε επιλέξτε Προβολή → Στοιχιζόμενα παράθυρα, στη γραμμή μενού." ExtraBrowsers="Προσαρμοσμένες αποβάθρες προγράμματος περιήγησης" ExtraBrowsers.DockName="Όνομα Dock" @@ -111,6 +113,7 @@ Auth.Authing.Text="Πιστοποίηση με %1, παρακαλώ περιμέ Auth.AuthFailure.Title="Αποτυχία ελέγχου ταυτότητας" Auth.AuthFailure.Text="Απέτυχε η πιστοποίηση με %1:\n\n%2: %3" Auth.InvalidScope.Title="Απαιτείται πιστοποίηση" +Auth.InvalidScope.Text="Οι απαιτήσεις πιστοποίησης για το %1 έχουν αλλάξει. Κάποιες δυνατότητες μπορεί να μην είναι διαθέσιμες." Auth.LoadingChannel.Title="Φόρτωση πληροφοριών καναλιού..." Auth.ChannelFailure.Title="Απέτυχε η φόρτωση του καναλιού" Auth.Chat="Συνομιλία" @@ -140,6 +143,7 @@ Basic.AutoConfig.StartPage.PrioritizeStreaming="Βελτιστοποίηση γ Basic.AutoConfig.StartPage.PrioritizeRecording="Βελτιστοποίηση μόνο για καταγραφή, όχι για ροή" Basic.AutoConfig.StartPage.PrioritizeVirtualCam="Θα χρησιμοποιήσω μόνο την εικονική κάμερα" Basic.AutoConfig.VideoPage="Ρυθμίσεις βίντεο" +Basic.AutoConfig.VideoPage.SubTitle="Καθορίστε τις ρυθμίσεις βίντεο που θα θέλατε να χρησιμοποιήσετε" Basic.AutoConfig.VideoPage.BaseResolution.UseCurrent="Χρήση Τρέχουσας (%1x%2)" Basic.AutoConfig.VideoPage.BaseResolution.Display="Οθόνη %1 (%2x%3)" Basic.AutoConfig.VideoPage.FPS.UseCurrent="Χρήση Τρεχόντων (%1)" @@ -151,7 +155,9 @@ Basic.AutoConfig.StreamPage.SubTitle="Παρακαλώ εισάγετε τις Basic.AutoConfig.StreamPage.ConnectAccount="Σύνδεση Λογαριασμού (προτείνεται)" Basic.AutoConfig.StreamPage.DisconnectAccount="Αποσύνδεση Λογαριασμού" Basic.AutoConfig.StreamPage.DisconnectAccount.Confirm.Title="Αποσύνδεση Λογαριασμού;" +Basic.AutoConfig.StreamPage.DisconnectAccount.Confirm.Text="Αυτή η αλλαγή θα εφαρμοστεί άμεσα. Θέλετε σίγουρα να αποσυνδεθείτε από το λογαριασμό σας;" Basic.AutoConfig.StreamPage.GetStreamKey="Κλειδί Ροής" +Basic.AutoConfig.StreamPage.MoreInfo="Περισσότερες πληροφορίες" Basic.AutoConfig.StreamPage.UseStreamKey="Χρησιμοποιήστε το κλειδί ζωντανής ροής" Basic.AutoConfig.StreamPage.Service="Υπηρεσία" Basic.AutoConfig.StreamPage.Service.ShowAll="Εμφάνιση Όλων..." @@ -180,6 +186,7 @@ Basic.AutoConfig.TestPage.Result.StreamingEncoder="Κωδικοποιητής Ρ Basic.AutoConfig.TestPage.Result.RecordingEncoder="Κωδικοποιητής Καταγραφής" Basic.AutoConfig.TestPage.Result.Header="Το πρόγραμμα έχει καθορίσει πως οι ακόλουθες ρυθμίσεις είναι οι πιο ιδανικές για σας:" Basic.AutoConfig.TestPage.Result.Footer="Για χρήση αυτών των ρυθμίσεων, κάντε κλικ στο κουμπί Εφαρμογή Ρυθμίσεων. Για να ξαναρυθμίσετε τις παραμέτρους του οδηγού και να προσπαθήσετε ξανά, κάντε κλικ στο κουμπί Πίσω. Για να ρυθμίσετε χειροκίνητα οι ίδιοι τις ρυθμίσεις, κάντε κλικ στο κουμπί Άκυρο και ανοίξτε τις ρυθμίσεις." +Basic.AutoConfig.Info="Ο οδηγός αυτόματης ρύθμισης παραμέτρων θα καθορίσει τις ιδανικές ρυθμίσεις για τα χαρακτηριστικά του υπολογιστή σας και την ταχύτητα της σύνδεσής σας." Basic.AutoConfig.RunAnytime="Αυτό μπορεί να τρέξει σε κάθε στιγμή πηγαίνοντας στο μενού εργαλίων." Basic.Stats="Στατιστικά" @@ -293,6 +300,8 @@ Output.BadPath.Title="Λάθος Διαδρομή Αρχείου" Output.BadPath.Text="Η προκαθορισμένη διαδρομή αρχείου δεν ειναι έγκυρη. Παρακαλώ ελέγξτε τις ρυθμίσεις σας για να επιβεβαιώσετε ότι έχει οριστεί μια έγκυρη διαδρομή αρχείου." LogReturnDialog="Ανέβασμα αρχείου καταγραφής επιτυχές" +LogReturnDialog.Description="Το αρχείο καταγραφής σας έχει ανέβει. Μπορείτε τώρα να μοιραστείτε το σύνδεσμο για βελτιώσεις και υποστήριξη." +LogReturnDialog.Description.Crash="Η αναφορά σφαλμάτων σας έχει ανέβει. Μπορείτε τώρα να μοιραστείτε το σύνδεσμο για βελτιώσεις." LogReturnDialog.CopyURL="Αντιγραφή Διεύθυνσης" LogReturnDialog.AnalyzeURL="Ανάλυση" LogReturnDialog.ErrorUploadingLog="Απέτυχε η μεταφόρτωση αρχείου καταγραφής" @@ -351,8 +360,6 @@ Deinterlacing.Yadif2x="Yadif 2x" Deinterlacing.TopFieldFirst="Επάνω Πεδίο Πρώτα" Deinterlacing.BottomFieldFirst="Κάτω Πεδίο Πρώτα" -VolControl.SliderUnmuted="Ρυθμιστής έντασης για '%1': %2" -VolControl.SliderMuted="Ρυθμιστής έντασης για '%1': %2 (προσωρινά σε σίγαση)" VolControl.Mute="Σίγαση '%1'" VolControl.Properties="Ιδιότητες για '%1'" @@ -368,6 +375,7 @@ Basic.Main.RenameSceneCollection.Title="Μετονομασία Συλλογής AddProfile.Title="Προσθήκη Προφίλ" AddProfile.Text="Παρακαλώ εισάγετε το όνομα του προφίλ" +AddProfile.WizardCheckbox="Εμφάνιση οδηγού αυτόματης ρύθμισης" RenameProfile.Title="Μετονομασία Προφίλ" @@ -382,6 +390,7 @@ Basic.SourceSelect.CreateNew="Δημιουργία νέας" Basic.SourceSelect.AddExisting="Προσθήκη Υπάρχουσας" Basic.SourceSelect.AddVisible="Να γίνει η πηγή ορατή" + Basic.PropertiesWindow="Ιδιότητες για '%1'" Basic.PropertiesWindow.AutoSelectFormat="%1 (αυτόματη επιλογή: %2)" Basic.PropertiesWindow.SelectColor="Επιλέξτε χρώμα" @@ -468,6 +477,8 @@ Basic.Main.StoppingReplayBuffer="Διακοπή Επανάληψης Προσω Basic.Main.StopStreaming="Διακοπή Ροής" Basic.Main.StoppingStreaming="Διακοπή Ροής..." Basic.Main.ForceStopStreaming="Διακοπή Ροής(απόρριψη καθυστέρησης)" +Basic.Main.ShowContextBar="Εμφάνιση γραμμής εργαλείων πηγής" +Basic.Main.HideContextBar="Απόκρυψη γραμμής εργαλείων πηγής" Basic.Main.StopVirtualCam="Σταματήστε την εικονική κάμερα" Basic.Main.Group="Ομάδα %1" Basic.Main.GroupItems="Ομάδα Επιλεγμένων Στοιχείων" @@ -520,10 +531,11 @@ Basic.MainMenu.Edit.AdvAudio="Ιδιότητες Ήχου για Προχωρη Basic.MainMenu.View="Προβολή (&V)" Basic.MainMenu.View.Toolbars="Γραμμές εργαλείων (&T)" -Basic.MainMenu.View.Docks="Μπάρες εφαρμογών" +Basic.MainMenu.View.Docks="Στοιχιζόμενα παράθυρα" Basic.MainMenu.View.Docks.ResetUI="Επαναφορά περιβάλλοντος χρήστη" Basic.MainMenu.View.Docks.LockUI="Κλείδωμα περιβάλλοντος χρήστη" Basic.MainMenu.View.Docks.CustomBrowserDocks="Προσαρμοσμένες αποβάθρες προγράμματος περιήγησης..." +Basic.MainMenu.View.ContextBar="Γραμμή εργαλείων πηγής" Basic.MainMenu.View.SceneTransitions="Μεταβάσεις Σκηνών(&C)" Basic.MainMenu.View.SourceIcons="Πηγές Εικονίδια" Basic.MainMenu.View.StatusBar="Γραμμή κατάστασης(&S)" @@ -623,7 +635,6 @@ Basic.Settings.Output.Format="Μορφή Καταγραφής" Basic.Settings.Output.Encoder="Κωδικοποιητής" Basic.Settings.Output.SelectDirectory="Επιλέξτε Φάκελο Καταγραφής" Basic.Settings.Output.SelectFile="Επιλέξτε Αρχείο Καταγραφής" -Basic.Settings.Output.EnforceBitrate="Επιβολή υπηρεσίας ροής στα όρια ρυθμού μετάδοσης bits" Basic.Settings.Output.DynamicBitrate="Δυναμική αλλαγή ρυθμός μετάδοσης bit για τη διαχείρηση της συμφόρησης" Basic.Settings.Output.DynamicBitrate.Beta="Δυναμική αλλαγή ρυθμός μετάδοσης bit για τη διαχείρηση της συμφόρησης(Δοκιμαστική Έκδοση)" Basic.Settings.Output.Mode="Λειτουργία Εξόδου" @@ -631,6 +642,7 @@ Basic.Settings.Output.Mode.Simple="Απλό" Basic.Settings.Output.Mode.Adv="Για Προχωρημένους" Basic.Settings.Output.Mode.FFmpeg="Έξοδος FFmpeg" Basic.Settings.Output.UseReplayBuffer="Ενεργοποίηση Επανάληψης Προσωρινής Μνήμης" +Basic.Settings.Output.ReplayBuffer.SecondsMax="Μέγιστος Χρόνος Επανάληψης" Basic.Settings.Output.ReplayBuffer.MegabytesMax="Μέγιστη Μνήμη (Megabytes)" Basic.Settings.Output.ReplayBuffer.Estimate="Εκτιμώμενη χρήση μνήμης: %1 MB" Basic.Settings.Output.ReplayBuffer.EstimateUnknown="Δεν είναι δυνατή η εκτίμηση της χρήσης μνήμης. Ορίστε μέγιστο όριο μνήμης." @@ -642,8 +654,7 @@ 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="Προειδοποίηση: Το βίντεο ροής ρυθμού μετάδοσης bit θα οριστεί σε %1, που είναι το ανώτερο όριο για την τρέχουσα υπηρεσία συνεχούς ροής. Εάν είστε βέβαιοι ότι θέλετε να υπερβείτε το %1, ενεργοποιήστε τις επιλογές του κωδικοποιητή για προχωρημένους και αποεπιλέξτε την επιλογή «Επιβολή υπηρεσίας ροής στα όρια ρυθμού μετάδοσης bit»." -Basic.Settings.Output.Simple.Warn.AudioBitrate="Προειδοποίηση: Ο ρυθμος μετάδοσης bit του ήχου ροής θα οριστεί στο %1, που είναι το ανώτατο όριο για την τρέχουσα υπηρεσία συνεχούς ροής. Εάν είστε βέβαιοι ότι θέλετε να υπερβείτε το %1, ενεργοποιήστε τις επιλογές του κωδικοποιητή για προχωρημένους και αποεπιλέξτε την επιλογή «Επιβολή υπηρεσίας ροής στα όρια ρυθμού μετάδοσης bit»." +Basic.Settings.Output.Simple.Warn.CannotPause="Προειδοποίηση: Δε μπορείτε να σταματήσετε την καταγραφή εάν η ποιότητα εγγραφής έχει οριστεί σε \"Ίδιο με τη ροή\"." Basic.Settings.Output.Simple.Warn.Encoder="Προειδοποίηση: Η καταγραφή με χρήση κωδικοποιητή λογισμικού σε διαφορετική ποιότητα από την ροή θα απαιτήσει πρόσθετη χρήση της CPU, αν πραγματοποιήσετε ταυτόχρονα μετάδοση ροής και καταγραφή." Basic.Settings.Output.Simple.Warn.Lossless="Προειδοποίηση: Η ποιότητα χωρίς απώλειες αυξάνει πολύ το μέγεθος των αρχείων! Η ποιότητα χωρίς απώλειες ποιότητας θα καταλάβει 7 gigabyte χώρο στον σκληρό δίσκο ανά λεπτό, σε υψηλές αναλύσεις και ρυθμό καρέ. Η επιλογή χωρίς απώλειες δεν συνιστάται για μεγάλες σε διάρκεια καταγραφές, εκτός και αν έχετε πολύ ελεύθερο χώρο διαθέσιμο στο σκληρό σας δίσκο." Basic.Settings.Output.Simple.Warn.Lossless.Msg="Είστε σίγουρος ότι θέλετε να χρησιμοποιήσετε την επιλογή ποιότητα χωρίς απώλειες;" @@ -658,6 +669,7 @@ Basic.Settings.Output.AudioBitrate="Ρυθμός Μετάδοσης Bit του Basic.Settings.Output.Reconnect="Αυτόματη Επανασύνδεση" Basic.Settings.Output.MaxRetries="Μέγιστος Αριθμός Επαναλήψεων" Basic.Settings.Output.Advanced="Ενεργοποίηση Ρυθμίσεων Κωδικοποιητή Για Προχωρημένους" +Basic.Settings.Output.EncoderPreset="Προεπιλογές Κωδικοποιητή" Basic.Settings.Output.CustomEncoderSettings="Προσαρμοσμένες Ρυθμίσεις Κωδικοποιητή" Basic.Settings.Output.CustomMuxerSettings="Προσαρμοσμένες Ρυθμίσεις Πολυπλέκτη" Basic.Settings.Output.NoSpaceFileName="Δημιουργία Ονόματος Αρχείου χωρίς Κενό" @@ -665,7 +677,6 @@ 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" @@ -702,6 +713,8 @@ Basic.Settings.Output.Adv.FFmpeg.MuxerSettings="Ρυθμίσεις Πολυπλ Basic.Settings.Output.Adv.FFmpeg.GOPSize="Διάστημα καρέ-κλειδιού (σε καρέ)" Basic.Settings.Output.Adv.FFmpeg.IgnoreCodecCompat="Προβολή όλων των codecs (ακόμα και αν δεν είναι συμβατοί)" +Screenshot="Έξοδος Στιγμιότυπου Οθόνης" +Screenshot.SourceHotkey="Επιλεγμένη Προέλευση Στιγμιότυπου Οθόνης" Screenshot.StudioProgram="Στιγμιότυπο οθόνης(Program)" Screenshot.Preview="Στιγμιότυπο οθόνης(Preview)" Screenshot.Scene="Στιγμιότυπο οθόνης(Scene)" @@ -737,6 +750,7 @@ Basic.Settings.Audio="Ήχος" Basic.Settings.Audio.SampleRate="Ρυθμός Δειγματοληψίας" Basic.Settings.Audio.Channels="Κανάλια" Basic.Settings.Audio.Meters="Μέτρα" +Basic.Settings.Audio.MeterDecayRate="Ρυθμός Απόσβεσης" Basic.Settings.Audio.MeterDecayRate.Fast="Γρήγορος" Basic.Settings.Audio.MeterDecayRate.Medium="Μεσαίος (τύπος Ι PPM)" Basic.Settings.Audio.MeterDecayRate.Slow="Αργός (Τύπος ΙΙ PPM)" @@ -909,5 +923,16 @@ Importer.AutomaticCollectionPrompt="Αυτόματη Αναζήτηση για Restart="Επανεκκίνηση" NeedsRestart="Το OBS Studio χρειάζεται να γίνει επανεκκίνηση. Θέλετε να το κάνετε επανεκκίνηση τώρα;" +ContextBar.NoSelectedSource="Δεν επιλέχθηκε πηγή" +ContextBar.ResetTransform="Επαναφορά Μετασχηματισμού" +ContextBar.FitToCanvas="Προσαρμογή στον Καμβά" +ContextBar.MediaControls.PlayMedia="Αναπαραγωγή Πολυμέσων" +ContextBar.MediaControls.PauseMedia="Παύση Πολυμέσων" +ContextBar.MediaControls.StopMedia="Διακοπή Πολυμέσων" +ContextBar.MediaControls.RestartMedia="Επανεκκίνηση Πολυμέσων" +ContextBar.MediaControls.PlaylistNext="Επόμενο στη Λίστα" +ContextBar.MediaControls.PlaylistPrevious="Προηγούμενο στη Λίστα" +ContextBar.MediaControls.MediaProperties="Ιδιότητες Πολυμέσων" +ContextBar.MediaControls.BlindSeek="Μενού Αναζήτησης Πολυμέσων" diff --git a/UI/data/locale/en-GB.ini b/UI/data/locale/en-GB.ini index c89a1cd..3a99315 100644 --- a/UI/data/locale/en-GB.ini +++ b/UI/data/locale/en-GB.ini @@ -93,6 +93,7 @@ LockVolume="Lock Volume" LogViewer="Log Viewer" ShowOnStartup="Show on startup" OpenFile="Open file" +AddValue="Add %1" AlreadyRunning.Title="OBS is already running" AlreadyRunning.Text="OBS is already running! Unless you meant to do this, please shut down any existing instances of OBS before trying to run a new instance. If you have OBS set to minimise to the system tray, please check to see if it's still running there." @@ -160,6 +161,7 @@ Basic.AutoConfig.StreamPage.DisconnectAccount="Disconnect Account" Basic.AutoConfig.StreamPage.DisconnectAccount.Confirm.Title="Disconnect Account?" Basic.AutoConfig.StreamPage.DisconnectAccount.Confirm.Text="This change will apply immediately. Are you sure you want to disconnect your account?" Basic.AutoConfig.StreamPage.GetStreamKey="Get Stream Key" +Basic.AutoConfig.StreamPage.MoreInfo="More Info" Basic.AutoConfig.StreamPage.UseStreamKey="Use Stream Key" Basic.AutoConfig.StreamPage.Service="Service" Basic.AutoConfig.StreamPage.Service.ShowAll="Show All..." @@ -236,22 +238,72 @@ QuickTransitions.EditProperties="Duplicate Sources" QuickTransitions.EditPropertiesTT="When editing the same scene, allows editing properties of sources without modifying the output.\nThis can only be used if 'Duplicate Scene' is enabled.\nCertain sources (such as capture or media sources) do not support this and cannot be edited separately.\nChanging this value will reset the current output scene (if it still exists).\n\nWarning: Because sources will be duplicated, this may require extra system or video resources." QuickTransitions.HotkeyName="Quick Transition: %1" +Basic.AddTransition="Add Configurable Transition" +Basic.RemoveTransition="Remove Configurable Transition" +Basic.TransitionProperties="Transition Properties" +Basic.SceneTransitions="Scene Transitions" +Basic.TransitionDuration="Duration" +Basic.TogglePreviewProgramMode="Studio Mode" +TransitionNameDlg.Text="Please enter the name of the transition" +TransitionNameDlg.Title="Transition Name" +TitleBar.Profile="Profile" +TitleBar.Scenes="Scenes" +NameExists.Title="Name already exists" +NameExists.Text="The name is already in use." +NoNameEntered.Title="Please enter a valid name" +NoNameEntered.Text="You cannot use empty names." +ConfirmStart.Title="Start Stream?" +ConfirmStart.Text="Are you sure you want to start the stream?" +ConfirmStop.Title="Stop Stream?" +ConfirmStop.Text="Are you sure you want to stop the stream?" +ConfirmStopRecord.Title="Stop Recording?" +ConfirmStopRecord.Text="Are you sure you want to stop recording?" +ConfirmBWTest.Title="Start Bandwidth Test?" +ConfirmBWTest.Text="You have OBS configured in bandwidth test mode. This mode allows for network testing without your channel going live. Once you are done testing, you will need to disable it in order for viewers to be able to see your stream.\n\nDo you want to continue?" +ConfirmExit.Title="Exit OBS?" +ConfirmExit.Text="OBS is currently active. All streams/recordings will be shut down. Are you sure you wish to exit?" +ConfirmRemove.Title="Confirm Remove" +ConfirmRemove.Text="Are you sure you wish to remove '$1'?" +ConfirmRemove.TextMultiple="Are you sure you wish to remove %1 items?" +Output.StartStreamFailed="Failed to start streaming" +Output.StartRecordingFailed="Failed to start recording" +Output.StartReplayFailed="Failed to start replay buffer" +Output.StartFailedGeneric="Starting the output failed. Please check the log for details.\n\nNote: If you are using the NVENC or AMD encoders, make sure your video drivers are up to date." +Output.ReplayBuffer.PauseWarning.Title="Cannot save replays while paused" +Output.ReplayBuffer.PauseWarning.Text="Warning: Replays cannot be saved while recording is paused." +Output.ConnectFail.Title="Failed to connect" +Output.ConnectFail.BadPath="Invalid Path or Connection URL. Please check your settings to confirm that they are valid." +Output.ConnectFail.ConnectFailed="Failed to connect to server" +Output.ConnectFail.InvalidStream="Could not access the specified channel or stream key, please double-check your stream key. If it is correct, there may be a problem connecting to the server." +Output.ConnectFail.Error="An unexpected error occurred when trying to connect to the server. More information in the log file." +Output.ConnectFail.Disconnected="Disconnected from server." +Output.StreamEncodeError.Title="Encoding error" +Output.StreamEncodeError.Msg="An encoder error occurred while streaming." +Output.RecordFail.Title="Failed to start recording" +Output.RecordFail.Unsupported="The output format is either unsupported or does not support more than one audio track. Please check your settings and try again." +Output.RecordNoSpace.Title="Insufficient disk space" +Output.RecordNoSpace.Msg="There is not sufficient disk space to continue recording." +Output.RecordError.Title="Recording error" +Output.RecordError.Msg="An unspecified error occurred while recording." +Output.RecordError.EncodeErrorMsg="An encoder error occurred while recording." +Output.BadPath.Title="Bad File Path" +Output.BadPath.Text="The configured file output path is invalid. Please check your settings to confirm that a valid file path has been set." LogReturnDialog="Log Upload Successful" LogReturnDialog.Description="Your log file has been uploaded. You can now share the URL for debugging or support purposes." @@ -262,95 +314,663 @@ LogReturnDialog.ErrorUploadingLog="Error uploading log file" Remux.SourceFile="OBS Recording" Remux.TargetFile="Target File" +Remux.Remux="Remux" +Remux.Stop="Stop Remuxing" +Remux.ClearFinished="Clear Finished Items" +Remux.ClearAll="Clear All Items" +Remux.OBSRecording="OBS Recording" +Remux.FinishedTitle="Remuxing finished" +Remux.Finished="Recording remuxed" +Remux.FinishedError="Recording remuxed, but the file may be incomplete" +Remux.SelectRecording="Select OBS Recording..." +Remux.SelectTarget="Select target file..." +Remux.FileExistsTitle="Target files exist" +Remux.FileExists="The following target files already exist. Do you want to replace them?" +Remux.ExitUnfinishedTitle="Remuxing in progress" +Remux.ExitUnfinished="Remuxing is not finished, stopping now may render the target file unusable.\nAre you sure you want to stop remuxing?" +Remux.HelpText="Drop files in this window to remux, or select an empty \"OBS Recording\" cell to browse for a file." + +UpdateAvailable="New Update Available" +UpdateAvailable.Text="Version %1.%2.%3 is now available. Click here to download" + +Basic.DesktopDevice1="Desktop Audio" +Basic.DesktopDevice2="Desktop Audio 2" +Basic.AuxDevice1="Mic/Aux" +Basic.AuxDevice2="Mic/Aux 2" +Basic.AuxDevice3="Mic/Aux 3" +Basic.AuxDevice4="Mic/Aux 4" + +Basic.Scene="Scene" +Basic.DisplayCapture="Display Capture" + +Basic.Main.PreviewConextMenu.Enable="Enable Preview" + +Basic.Main.Preview.Disable="Disable Preview" + +ScaleFiltering="Scale Filtering" +ScaleFiltering.Point="Point" +ScaleFiltering.Bilinear="Bilinear" +ScaleFiltering.Bicubic="Bicubic" +ScaleFiltering.Lanczos="Lanczos" +ScaleFiltering.Area="Area" + +Deinterlacing="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="Top Field First" +Deinterlacing.BottomFieldFirst="Bottom Field First" + +VolControl.SliderUnmuted="Volume slider for '%1':" +VolControl.SliderMuted="Volume slider for '%1': (currently muted)" +VolControl.Mute="Mute '%1'" +VolControl.Properties="Properties for '%1'" + +Basic.Main.AddSceneDlg.Title="Add Scene" +Basic.Main.AddSceneDlg.Text="Please enter the name of the scene" + +Basic.Main.DefaultSceneName.Text="Scene %1" + +Basic.Main.AddSceneCollection.Title="Add Scene Collection" +Basic.Main.AddSceneCollection.Text="Please enter the name of the scene collection" + +Basic.Main.RenameSceneCollection.Title="Rename Scene Collection" + +AddProfile.Title="Add Profile" +AddProfile.Text="Please enter the name of the profile" +AddProfile.WizardCheckbox="Show auto-configuration wizard" + +RenameProfile.Title="Rename Profile" + +Basic.Main.MixerRename.Title="Rename Audio Source" +Basic.Main.MixerRename.Text="Please enter the name of the audio source" +Basic.Main.PreviewDisabled="Preview is currently disabled" +Basic.SourceSelect="Create/Select Source" +Basic.SourceSelect.CreateNew="Create new" +Basic.SourceSelect.AddExisting="Add Existing" +Basic.SourceSelect.AddVisible="Make source visible" +Basic.Main.Sources.Visibility="Visibility" +Basic.Main.Sources.VisibilityDescription="Controls the visibility of '%1' in the canvas" +Basic.Main.Sources.Lock="Lock" +Basic.Main.Sources.LockDescription="Locks the position and scale of '%1' in the canvas" - - - - - - - - - - - - - - +Basic.PropertiesWindow="Properties for '%1'" +Basic.PropertiesWindow.AutoSelectFormat="%1 (autoselect: %2)" Basic.PropertiesWindow.SelectColor="Select colour" +Basic.PropertiesWindow.SelectFont="Select font" +Basic.PropertiesWindow.ConfirmTitle="Settings Changed" +Basic.PropertiesWindow.Confirm="There are unsaved changes. Do you want to keep them?" +Basic.PropertiesWindow.NoProperties="No properties available" +Basic.PropertiesWindow.AddFiles="Add Files" +Basic.PropertiesWindow.AddDir="Add Directory" +Basic.PropertiesWindow.AddURL="Add Path/URL" +Basic.PropertiesWindow.AddEditableListDir="Add directory to '%1'" +Basic.PropertiesWindow.AddEditableListFiles="Add files to '%1'" +Basic.PropertiesWindow.AddEditableListEntry="Add entry to '%1'" +Basic.PropertiesWindow.EditEditableListEntry="Edit entry from '%1'" +Basic.PropertiesView.FPS.Simple="Simple FPS Values" +Basic.PropertiesView.FPS.Rational="Rational FPS Values" +Basic.PropertiesView.FPS.ValidFPSRanges="Valid FPS Ranges:" +Basic.InteractionWindow="Interacting with '%1'" +Basic.StatusBar.Reconnecting="Disconnected, reconnecting in %2 second(s) (attempt %1)" +Basic.StatusBar.AttemptingReconnect="Attempting to reconnect... (attempt %1)" +Basic.StatusBar.ReconnectSuccessful="Reconnection successful" +Basic.StatusBar.Delay="Delay (%1 sec)" +Basic.StatusBar.DelayStartingIn="Delay (starting in %1 sec)" +Basic.StatusBar.DelayStoppingIn="Delay (stopping in %1 sec)" +Basic.StatusBar.DelayStartingStoppingIn="Delay (stopping in %1 sec, starting in %2 sec)" +Basic.Filters="Filters" +Basic.Filters.AsyncFilters="Audio/Video Filters" +Basic.Filters.AudioFilters="Audio Filters" +Basic.Filters.EffectFilters="Effect Filters" +Basic.Filters.Title="Filters for '%1'" +Basic.Filters.AddFilter.Title="Filter name" +Basic.Filters.AddFilter.Text="Please specify the name of the filter" +Basic.TransformWindow="Scene Item Transform" +Basic.TransformWindow.Position="Position" +Basic.TransformWindow.Rotation="Rotation" +Basic.TransformWindow.Size="Size" +Basic.TransformWindow.Alignment="Positional Alignment" +Basic.TransformWindow.BoundsType="Bounding Box Type" +Basic.TransformWindow.BoundsAlignment="Alignment in Bounding Box" +Basic.TransformWindow.Bounds="Bounding Box Size" +Basic.TransformWindow.Crop="Crop" +Basic.TransformWindow.Alignment.TopLeft="Top Left" Basic.TransformWindow.Alignment.TopCenter="Top Centre" +Basic.TransformWindow.Alignment.TopRight="Top Right" Basic.TransformWindow.Alignment.CenterLeft="Centre Left" Basic.TransformWindow.Alignment.Center="Centre" Basic.TransformWindow.Alignment.CenterRight="Centre Right" +Basic.TransformWindow.Alignment.BottomLeft="Bottom Left" Basic.TransformWindow.Alignment.BottomCenter="Bottom Centre" +Basic.TransformWindow.Alignment.BottomRight="Bottom Right" +Basic.TransformWindow.BoundsType.None="No bounds" +Basic.TransformWindow.BoundsType.MaxOnly="Maximum size only" +Basic.TransformWindow.BoundsType.ScaleInner="Scale to inner bounds" +Basic.TransformWindow.BoundsType.ScaleOuter="Scale to outer bounds" +Basic.TransformWindow.BoundsType.ScaleToWidth="Scale to width of bounds" +Basic.TransformWindow.BoundsType.ScaleToHeight="Scale to height of bounds" +Basic.TransformWindow.BoundsType.Stretch="Stretch to bounds" +Basic.Main.AddSourceHelp.Title="Cannot Add Source" +Basic.Main.AddSourceHelp.Text="You need to have at least 1 scene to add a source." +Basic.Main.Scenes="Scenes" +Basic.Main.Sources="Sources" +Basic.Main.Controls="Controls" +Basic.Main.Connecting="Connecting..." +Basic.Main.StartRecording="Start Recording" +Basic.Main.StartReplayBuffer="Start Replay Buffer" +Basic.Main.SaveReplay="Save Replay" +Basic.Main.StartStreaming="Start Streaming" +Basic.Main.StartVirtualCam="Start Virtual Camera" +Basic.Main.StopRecording="Stop Recording" +Basic.Main.PauseRecording="Pause Recording" +Basic.Main.UnpauseRecording="Unpause Recording" +Basic.Main.StoppingRecording="Stopping Recording..." +Basic.Main.StopReplayBuffer="Stop Replay Buffer" +Basic.Main.StoppingReplayBuffer="Stopping Replay Buffer..." +Basic.Main.StopStreaming="Stop Streaming" +Basic.Main.StoppingStreaming="Stopping Stream..." +Basic.Main.ForceStopStreaming="Stop Streaming (discard delay)" +Basic.Main.ShowContextBar="Show Source Toolbar" +Basic.Main.HideContextBar="Hide Source Toolbar" +Basic.Main.StopVirtualCam="Stop Virtual Camera" +Basic.Main.Group="Group %1" +Basic.Main.GroupItems="Group Selected Items" +Basic.Main.Ungroup="Ungroup" +Basic.Main.GridMode="Grid Mode" +Basic.Main.ListMode="List Mode" +Basic.MainMenu.File="&File" +Basic.MainMenu.File.Export="&Export" +Basic.MainMenu.File.Import="&Import" +Basic.MainMenu.File.ShowRecordings="Show &Recordings" +Basic.MainMenu.File.Remux="Re&mux Recordings" +Basic.MainMenu.File.Settings="&Settings" +Basic.MainMenu.File.ShowSettingsFolder="Show Settings Folder" +Basic.MainMenu.File.ShowProfileFolder="Show Profile Folder" +Basic.MainMenu.AlwaysOnTop="&Always On Top" +Basic.MainMenu.File.Exit="E&xit" +Basic.MainMenu.Edit="&Edit" +Basic.MainMenu.Edit.Undo="&Undo" +Basic.MainMenu.Edit.Redo="&Redo" +Basic.MainMenu.Edit.UndoAction="&Undo $1" +Basic.MainMenu.Edit.RedoAction="&Redo $1" +Basic.MainMenu.Edit.LockPreview="&Lock Preview" +Basic.MainMenu.Edit.Scale="Preview &Scaling" +Basic.MainMenu.Edit.Scale.Window="Scale to Window" +Basic.MainMenu.Edit.Scale.Canvas="Canvas (%1x%2)" +Basic.MainMenu.Edit.Scale.Output="Output (%1x%2)" +Basic.MainMenu.Edit.Transform="&Transform" +Basic.MainMenu.Edit.Transform.EditTransform="&Edit Transform..." +Basic.MainMenu.Edit.Transform.CopyTransform="Copy Transform" +Basic.MainMenu.Edit.Transform.PasteTransform="Paste Transform" +Basic.MainMenu.Edit.Transform.ResetTransform="&Reset Transform" +Basic.MainMenu.Edit.Transform.Rotate90CW="Rotate 90 degrees Clockwise" +Basic.MainMenu.Edit.Transform.Rotate90CCW="Rotate 90 degrees Anti-Clockwise" +Basic.MainMenu.Edit.Transform.Rotate180="Rotate 180 degrees" +Basic.MainMenu.Edit.Transform.FlipHorizontal="Flip &Horizontal" +Basic.MainMenu.Edit.Transform.FlipVertical="Flip &Vertical" +Basic.MainMenu.Edit.Transform.FitToScreen="&Fit to screen" +Basic.MainMenu.Edit.Transform.StretchToScreen="&Stretch to screen" Basic.MainMenu.Edit.Transform.CenterToScreen="&Centre to screen" Basic.MainMenu.Edit.Transform.VerticalCenter="Centre Vertically" Basic.MainMenu.Edit.Transform.HorizontalCenter="Centre Horizontally" +Basic.MainMenu.Edit.Order="&Order" +Basic.MainMenu.Edit.Order.MoveUp="Move &Up" +Basic.MainMenu.Edit.Order.MoveDown="Move &Down" +Basic.MainMenu.Edit.Order.MoveToTop="Move to &Top" +Basic.MainMenu.Edit.Order.MoveToBottom="Move to &Bottom" +Basic.MainMenu.Edit.AdvAudio="&Advanced Audio Properties" +Basic.MainMenu.View="&View" +Basic.MainMenu.View.Toolbars="&Toolbars" +Basic.MainMenu.View.Docks="Docks" +Basic.MainMenu.View.Docks.ResetUI="Reset UI" +Basic.MainMenu.View.Docks.LockUI="Lock UI" +Basic.MainMenu.View.Docks.CustomBrowserDocks="Custom Browser Docks..." +Basic.MainMenu.View.ListboxToolbars="Scene/Source List Buttons" +Basic.MainMenu.View.ContextBar="Source Toolbar" +Basic.MainMenu.View.SceneTransitions="S&cene Transitions" +Basic.MainMenu.View.SourceIcons="Source &Icons" +Basic.MainMenu.View.StatusBar="&Status Bar" +Basic.MainMenu.View.Fullscreen.Interface="Fullscreen Interface" +Basic.MainMenu.SceneCollection="&Scene Collection" +Basic.MainMenu.Profile="&Profile" +Basic.MainMenu.Profile.Import="Import Profile" +Basic.MainMenu.Profile.Export="Export Profile" +Basic.MainMenu.SceneCollection.Import="Import Scene Collection" +Basic.MainMenu.SceneCollection.Export="Export Scene Collection" +Basic.MainMenu.Profile.Exists="The profile already exists" +Basic.MainMenu.SceneCollection.Exists="The scene collection already exists" +Basic.MainMenu.Tools="&Tools" +Basic.MainMenu.Help="&Help" +Basic.MainMenu.Help.HelpPortal="Help &Portal" +Basic.MainMenu.Help.Website="Visit &Website" +Basic.MainMenu.Help.Discord="Join &Discord Server" +Basic.MainMenu.Help.Logs="&Log Files" +Basic.MainMenu.Help.Logs.ShowLogs="&Show Log Files" +Basic.MainMenu.Help.Logs.UploadCurrentLog="Upload &Current Log File" +Basic.MainMenu.Help.Logs.UploadLastLog="Upload &Last Log File" +Basic.MainMenu.Help.Logs.ViewCurrentLog="&View Current Log" +Basic.MainMenu.Help.CheckForUpdates="Check For Updates" +Basic.MainMenu.Help.CrashLogs="Crash &Reports" +Basic.MainMenu.Help.CrashLogs.ShowLogs="&Show Crash Reports" +Basic.MainMenu.Help.CrashLogs.UploadLastLog="Upload &Last Crash Report" +Basic.MainMenu.Help.About="&About" +Basic.Settings.ProgramRestart="The program must be restarted for these settings to take effect." +Basic.Settings.ConfirmTitle="Confirm Changes" +Basic.Settings.Confirm="You have unsaved changes. Save changes?" +Basic.Settings.General="General" +Basic.Settings.General.Theme="Theme" +Basic.Settings.General.Language="Language" +Basic.Settings.General.EnableAutoUpdates="Automatically check for updates on startup" +Basic.Settings.General.OpenStatsOnStartup="Open stats dialogue on startup" +Basic.Settings.General.WarnBeforeStartingStream="Show confirmation dialogue when starting streams" +Basic.Settings.General.WarnBeforeStoppingStream="Show confirmation dialogue when stopping streams" +Basic.Settings.General.WarnBeforeStoppingRecord="Show confirmation dialogue when stopping recording" +Basic.Settings.General.Projectors="Projectors" +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 centre" +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.ReplayBufferWhileStreaming="Automatically start replay buffer when streaming" +Basic.Settings.General.KeepReplayBufferStreamStops="Keep replay buffer active when stream stops" +Basic.Settings.General.SysTray="System Tray" Basic.Settings.General.SysTrayWhenStarted="Minimise to system tray when started" Basic.Settings.General.SystemTrayHideMinimize="Always minimise to system tray instead of task bar" +Basic.Settings.General.SaveProjectors="Save projectors on exit" +Basic.Settings.General.Preview="Preview" +Basic.Settings.General.OverflowHidden="Hide overflow" +Basic.Settings.General.OverflowAlwaysVisible="Overflow always visible" +Basic.Settings.General.OverflowSelectionHidden="Show overflow even when source is invisible" +Basic.Settings.General.Importers="Importers" +Basic.Settings.General.AutomaticCollectionSearch="Search known locations for scene collections when importing" +Basic.Settings.General.SwitchOnDoubleClick="Transition to scene when double-clicked" +Basic.Settings.General.StudioPortraitLayout="Enable portrait/vertical layout" +Basic.Settings.General.TogglePreviewProgramLabels="Show preview/program labels" +Basic.Settings.General.Multiview="Multiview" +Basic.Settings.General.Multiview.MouseSwitch="Click to switch between scenes" +Basic.Settings.General.Multiview.DrawSourceNames="Show scene names" +Basic.Settings.General.Multiview.DrawSafeAreas="Draw safe areas (EBU R 95)" +Basic.Settings.General.MultiviewLayout="Multiview Layout" +Basic.Settings.General.MultiviewLayout.Horizontal.Top="Horizontal, Top (8 Scenes)" +Basic.Settings.General.MultiviewLayout.Horizontal.Bottom="Horizontal, Bottom (8 Scenes)" +Basic.Settings.General.MultiviewLayout.Vertical.Left="Vertical, Left (8 Scenes)" +Basic.Settings.General.MultiviewLayout.Vertical.Right="Vertical, Right (8 Scenes)" +Basic.Settings.General.MultiviewLayout.Horizontal.Extended.Top="Horizontal, Top (24 Scenes)" +Basic.Settings.Stream="Stream" +Basic.Settings.Stream.StreamType="Stream Type" +Basic.Settings.Stream.Custom.UseAuthentication="Use authentication" +Basic.Settings.Stream.Custom.Username="Username" +Basic.Settings.Stream.Custom.Password="Password" +Basic.Settings.Stream.BandwidthTestMode="Enable Bandwidth Test Mode" +Basic.Settings.Stream.TTVAddon="Twitch Chat Add-Ons" +Basic.Settings.Stream.TTVAddon.None="None" +Basic.Settings.Stream.TTVAddon.Both="BetterTTV and FrankerFaceZ" +Basic.Settings.Stream.MissingSettingAlert="Missing Stream Setup" +Basic.Settings.Stream.StreamSettingsWarning="Open Settings" +Basic.Settings.Stream.MissingUrlAndApiKey="URL and Stream Key are missing.\n\nOpen settings to enter the URL and Stream Key in the 'stream' tab." +Basic.Settings.Stream.MissingUrl="Stream URL is missing.\n\nOpen settings to enter the URL in the 'Stream' tab." +Basic.Settings.Stream.MissingStreamKey="Stream key is missing.\n\nOpen settings to enter the stream key in the 'Stream' tab." +Basic.Settings.Stream.IgnoreRecommended="Ignore streaming service setting recommendations" +Basic.Settings.Stream.IgnoreRecommended.Warn.Title="Override Recommended Settings" +Basic.Settings.Stream.IgnoreRecommended.Warn.Text="Warning: Ignoring the service's limitations may result in degraded stream quality or prevent you from streaming.\n\nContinue?" +Basic.Settings.Stream.Recommended.MaxVideoBitrate="Maximum Video Bitrate: %1 kbps" +Basic.Settings.Stream.Recommended.MaxAudioBitrate="Maximum Audio Bitrate: %1 kbps" +Basic.Settings.Stream.Recommended.MaxResolution="Maximum Resolution: %1" +Basic.Settings.Stream.Recommended.MaxFPS="Maximum FPS: %1" +Basic.Settings.Output="Output" +Basic.Settings.Output.Format="Recording Format" +Basic.Settings.Output.Encoder="Encoder" +Basic.Settings.Output.SelectDirectory="Select Recording Directory" +Basic.Settings.Output.SelectFile="Select Recording File" +Basic.Settings.Output.DynamicBitrate="Dynamically change bitrate to manage congestion" +Basic.Settings.Output.DynamicBitrate.Beta="Dynamically change bitrate to manage congestion (Beta)" +Basic.Settings.Output.DynamicBitrate.TT="Instead of dropping frames to reduce congestion, dynamically changes bitrate on the fly.\n\nNote that this can increase delay to viewers if there is significant sudden congestion.\nWhen the bitrate drops, it can take up to a few minutes to restore.\n\nCurrently only supported for RTMP." +Basic.Settings.Output.Mode="Output Mode" +Basic.Settings.Output.Mode.Simple="Simple" +Basic.Settings.Output.Mode.Adv="Advanced" +Basic.Settings.Output.Mode.FFmpeg="FFmpeg Output" +Basic.Settings.Output.UseReplayBuffer="Enable Replay Buffer" +Basic.Settings.Output.ReplayBuffer.SecondsMax="Maximum Replay Time" +Basic.Settings.Output.ReplayBuffer.MegabytesMax="Maximum Memory (Megabytes)" +Basic.Settings.Output.ReplayBuffer.Estimate="Estimated memory usage: %1 MB" +Basic.Settings.Output.ReplayBuffer.EstimateUnknown="Cannot estimate memory usage. Please set maximum memory limit." +Basic.Settings.Output.ReplayBuffer.Prefix="Replay Buffer Filename Prefix" +Basic.Settings.Output.ReplayBuffer.Suffix="Suffix" +Basic.Settings.Output.Simple.SavePath="Recording Path" +Basic.Settings.Output.Simple.RecordingQuality="Recording Quality" +Basic.Settings.Output.Simple.RecordingQuality.Stream="Same as stream" +Basic.Settings.Output.Simple.RecordingQuality.Small="High Quality, Medium File Size" +Basic.Settings.Output.Simple.RecordingQuality.HQ="Indistinguishable Quality, Large File Size" +Basic.Settings.Output.Simple.RecordingQuality.Lossless="Lossless Quality, Tremendously Large File Size" +Basic.Settings.Output.Simple.Warn.VideoBitrate="Warning: The streaming video bitrate will be set to %1, which is the upper limit for the current streaming service." +Basic.Settings.Output.Simple.Warn.AudioBitrate="Warning: The streaming audio bitrate will be set to %1, which is the upper limit for the current streaming service." +Basic.Settings.Output.Simple.Warn.CannotPause="Warning: Recordings cannot be paused if the recording quality is set to \"Same as stream\"." +Basic.Settings.Output.Simple.Warn.Encoder="Warning: Recording with a software encoder at a different quality than the stream will require extra CPU usage if you stream and record at the same time." +Basic.Settings.Output.Simple.Warn.Lossless="Warning: Lossless quality generates tremendously large file sizes! Lossless quality can use upward of 7 Gigabytes of disk space per minute at high resolutions and frame rates. Lossless is not recommended for long recordings unless you have a very large amount of disk space available." +Basic.Settings.Output.Simple.Warn.Lossless.Msg="Are you sure you want to use lossless quality?" +Basic.Settings.Output.Simple.Warn.Lossless.Title="Lossless quality warning!" +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.Simple.TwitchVodTrack="Twitch VOD Track (Uses Track 2)" +Basic.Settings.Output.Warn.EnforceResolutionFPS.Title="Incompatible Resolution/Framerate" +Basic.Settings.Output.Warn.EnforceResolutionFPS.Msg="This streaming service does not support your current output resolution and/or framerate. They will be changed to the closest compatible value:\n\n%1\n\nDo you want to continue?" +Basic.Settings.Output.Warn.EnforceResolutionFPS.Resolution="Resolution: %1" +Basic.Settings.Output.Warn.EnforceResolutionFPS.FPS="FPS: %1" +Basic.Settings.Output.VideoBitrate="Video Bitrate" +Basic.Settings.Output.AudioBitrate="Audio Bitrate" +Basic.Settings.Output.Reconnect="Automatically Reconnect" +Basic.Settings.Output.RetryDelay="Retry Delay" +Basic.Settings.Output.MaxRetries="Maximum Retries" +Basic.Settings.Output.Advanced="Enable Advanced Encoder Settings" +Basic.Settings.Output.EncoderPreset="Encoder Preset" +Basic.Settings.Output.CustomEncoderSettings="Custom Encoder Settings" +Basic.Settings.Output.CustomMuxerSettings="Custom Muxer Settings" +Basic.Settings.Output.NoSpaceFileName="Generate File Name without Space" +Basic.Settings.Output.Adv.Rescale="Rescale Output" +Basic.Settings.Output.Adv.AudioTrack="Audio Track" +Basic.Settings.Output.Adv.Streaming="Streaming" +Basic.Settings.Output.Adv.Audio.Track1="Track 1" +Basic.Settings.Output.Adv.Audio.Track2="Track 2" +Basic.Settings.Output.Adv.Audio.Track3="Track 3" +Basic.Settings.Output.Adv.Audio.Track4="Track 4" +Basic.Settings.Output.Adv.Audio.Track5="Track 5" +Basic.Settings.Output.Adv.Audio.Track6="Track 6" +Basic.Settings.Output.Adv.TwitchVodTrack="Twitch VOD Track" +Basic.Settings.Output.Adv.Recording="Recording" +Basic.Settings.Output.Adv.Recording.RecType="Recording Type" +Basic.Settings.Output.Adv.Recording.Type="Type" +Basic.Settings.Output.Adv.Recording.Type.Standard="Standard" +Basic.Settings.Output.Adv.Recording.Type.FFmpegOutput="Custom Output (FFmpeg)" +Basic.Settings.Output.Adv.Recording.UseStreamEncoder="(Use stream encoder)" +Basic.Settings.Output.Adv.Recording.Filename="Filename Formatting" +Basic.Settings.Output.Adv.Recording.OverwriteIfExists="Overwrite if file exists" +Basic.Settings.Output.Adv.FFmpeg.Type="FFmpeg Output Type" +Basic.Settings.Output.Adv.FFmpeg.Type.URL="Output to URL" +Basic.Settings.Output.Adv.FFmpeg.Type.RecordToFile="Output to File" +Basic.Settings.Output.Adv.FFmpeg.SaveFilter.Common="Common recording formats" +Basic.Settings.Output.Adv.FFmpeg.SaveFilter.All="All Files" +Basic.Settings.Output.Adv.FFmpeg.SavePathURL="File path or URL" +Basic.Settings.Output.Adv.FFmpeg.Format="Container Format" +Basic.Settings.Output.Adv.FFmpeg.FormatAudio="Audio" +Basic.Settings.Output.Adv.FFmpeg.FormatVideo="Video" +Basic.Settings.Output.Adv.FFmpeg.FormatDefault="Default Format" +Basic.Settings.Output.Adv.FFmpeg.FormatDesc="Container Format Description" +Basic.Settings.Output.Adv.FFmpeg.FormatDescDef="Audio/Video Codec guessed from File path or URL" +Basic.Settings.Output.Adv.FFmpeg.AVEncoderDefault="Default Encoder" +Basic.Settings.Output.Adv.FFmpeg.AVEncoderDisable="Disable Encoder" +Basic.Settings.Output.Adv.FFmpeg.VEncoder="Video Encoder" +Basic.Settings.Output.Adv.FFmpeg.VEncoderSettings="Video Encoder Settings (if any)" +Basic.Settings.Output.Adv.FFmpeg.AEncoder="Audio Encoder" +Basic.Settings.Output.Adv.FFmpeg.AEncoderSettings="Audio Encoder Settings (if any)" +Basic.Settings.Output.Adv.FFmpeg.MuxerSettings="Muxer Settings (if any)" +Basic.Settings.Output.Adv.FFmpeg.GOPSize="Keyframe interval (frames)" +Basic.Settings.Output.Adv.FFmpeg.IgnoreCodecCompat="Show all codecs (even if potentially incompatible)" +Screenshot="Screenshot Output" +Screenshot.SourceHotkey="Screenshot Selected Source" +Screenshot.StudioProgram="Screenshot (Program)" +Screenshot.Preview="Screenshot (Preview)" +Screenshot.Scene="Screenshot (Scene)" +Screenshot.Source="Screenshot (Source)" 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\n%FPS\n%CRES\n%ORES\n%VF" +FilenameFormatting.TT="%CCYY Year, four digits\n%YY Year, last two digits (00-99)\n%MM Month as a decimal number (01-12)\n%DD Day of the month, zero-padded (01-31)\n%hh Hour in 24h format (00-23)\n%mm Minute (00-59)\n%ss Second (00-61)\n%% A % sign\n%a Abbreviated weekday name\n%A Full weekday name\n%b Abbreviated month name\n%B Full month name\n%d Day of the month, zero-padded (01-31)\n%H Hour in 24h format (00-23)\n%I Hour in 12h format (01-12)\n%m Month as a decimal number (01-12)\n%M Minute (00-59)\n%p AM or PM designation\n%S Second (00-61)\n%y Year, last two digits (00-99)\n%Y Year\n%z ISO 8601 offset from UTC in timezone\n%Z Timezone name or abbreviation\n%FPS Frames per second\n%CRES Base (canvas) resolution\n%ORES Output (scaled) resolution\n%VF Video format" +Basic.Settings.Video="Video" +Basic.Settings.Video.Adapter="Video Adapter" +Basic.Settings.Video.BaseResolution="Base (Canvas) Resolution" +Basic.Settings.Video.ScaledResolution="Output (Scaled) Resolution" +Basic.Settings.Video.DownscaleFilter="Downscale Filter" +Basic.Settings.Video.DisableAeroWindows="Disable Aero (Windows only)" +Basic.Settings.Video.FPS="FPS" +Basic.Settings.Video.FPSCommon="Common FPS Values" +Basic.Settings.Video.FPSInteger="Integer FPS Value" +Basic.Settings.Video.FPSFraction="Fractional FPS Value" +Basic.Settings.Video.Numerator="Numerator" +Basic.Settings.Video.Denominator="Denominator" +Basic.Settings.Video.Renderer="Renderer" +Basic.Settings.Video.InvalidResolution="Invalid resolution value. Must be [width]x[height] (i.e. 1920x1080)" +Basic.Settings.Video.CurrentlyActive="Video output is currently active. Please turn off any outputs to change video settings." +Basic.Settings.Video.DisableAero="Disable Aero" +Basic.Settings.Video.DownscaleFilter.Bilinear="Bilinear (Fastest, but blurry if scaling)" +Basic.Settings.Video.DownscaleFilter.Bicubic="Bicubic (Sharpened scaling, 16 samples)" +Basic.Settings.Video.DownscaleFilter.Lanczos="Lanczos (Sharpened scaling, 36 samples)" +Basic.Settings.Video.DownscaleFilter.Area="Area (Weighted sum, 4/6/9 samples)" +Basic.Settings.Audio="Audio" +Basic.Settings.Audio.SampleRate="Sample Rate" +Basic.Settings.Audio.Channels="Channels" +Basic.Settings.Audio.Meters="Meters" +Basic.Settings.Audio.MeterDecayRate="Decay Rate" +Basic.Settings.Audio.MeterDecayRate.Fast="Fast" +Basic.Settings.Audio.MeterDecayRate.Medium="Medium (Type I PPM)" +Basic.Settings.Audio.MeterDecayRate.Slow="Slow (Type II PPM)" +Basic.Settings.Audio.PeakMeterType="Peak Meter Type" +Basic.Settings.Audio.PeakMeterType.SamplePeak="Sample Peak" +Basic.Settings.Audio.PeakMeterType.TruePeak="True Peak (Higher CPU usage)" +Basic.Settings.Audio.MultiChannelWarning.Enabled="WARNING: Surround sound audio is enabled." +Basic.Settings.Audio.MultichannelWarning="If streaming, check to see if your streaming service supports both surround sound ingest and surround sound playback. Facebook 360 Live is one example where surround sound is fully supported. Although Facebook Live and YouTube Live both accept surround ingest, Facebook Live downmixes to stereo, and YouTube Live plays only two channels.\n\nOBS audio filters are compatible with surround sound, though VST plugin support isn't guaranteed." +Basic.Settings.Audio.MultichannelWarning.Title="Enable surround sound audio?" +Basic.Settings.Audio.MultichannelWarning.Confirm="Are you sure you want to enable surround sound audio?" +Basic.Settings.Audio.Devices="Global Audio Devices" +Basic.Settings.Audio.DesktopDevice="Desktop Audio" +Basic.Settings.Audio.DesktopDevice2="Desktop Audio 2" +Basic.Settings.Audio.AuxDevice="Mic/Auxiliary Audio" +Basic.Settings.Audio.AuxDevice2="Mic/Auxiliary Audio 2" +Basic.Settings.Audio.AuxDevice3="Mic/Auxiliary Audio 3" +Basic.Settings.Audio.AuxDevice4="Mic/Auxiliary Audio 4" +Basic.Settings.Audio.EnablePushToMute="Enable Push-to-mute" +Basic.Settings.Audio.PushToMuteDelay="Push-to-mute delay" +Basic.Settings.Audio.EnablePushToTalk="Enable Push-to-talk" +Basic.Settings.Audio.PushToTalkDelay="Push-to-talk delay" +Basic.Settings.Audio.UnknownAudioDevice="[Device not connected or not available]" +Basic.Settings.Audio.Disabled="Disabled" +Basic.Settings.Advanced="Advanced" +Basic.Settings.Advanced.General.ProcessPriority="Process Priority" +Basic.Settings.Advanced.General.ProcessPriority.High="High" +Basic.Settings.Advanced.General.ProcessPriority.AboveNormal="Above Normal" +Basic.Settings.Advanced.General.ProcessPriority.Normal="Normal" +Basic.Settings.Advanced.General.ProcessPriority.BelowNormal="Below Normal" +Basic.Settings.Advanced.General.ProcessPriority.Idle="Idle" Basic.Settings.Advanced.FormatWarning="Warning: Colour formats other than NV12 are primarily intended for recording, and are not recommended when streaming. Streaming may incur increased CPU usage due to colour format conversion." +Basic.Settings.Advanced.Audio.BufferingTime="Audio Buffering Time" Basic.Settings.Advanced.Video.ColorFormat="Colour Format" Basic.Settings.Advanced.Video.ColorSpace="Colour Space" Basic.Settings.Advanced.Video.ColorRange="Colour Range" +Basic.Settings.Advanced.Video.ColorRange.Partial="Partial" +Basic.Settings.Advanced.Video.ColorRange.Full="Full" +Basic.Settings.Advanced.Audio.MonitoringDevice="Monitoring Device" +Basic.Settings.Advanced.Audio.MonitoringDevice.Default="Default" +Basic.Settings.Advanced.Audio.DisableAudioDucking="Disable Windows audio ducking" +Basic.Settings.Advanced.StreamDelay="Stream Delay" +Basic.Settings.Advanced.StreamDelay.Duration="Duration" +Basic.Settings.Advanced.StreamDelay.Preserve="Preserve cutoff point (increase delay) when reconnecting" +Basic.Settings.Advanced.StreamDelay.MemoryUsage="Estimated Memory Usage: %1 MB" +Basic.Settings.Advanced.Network="Network" +Basic.Settings.Advanced.Network.BindToIP="Bind to IP" Basic.Settings.Advanced.Network.EnableNewSocketLoop="Enable network optimisations" +Basic.Settings.Advanced.Network.EnableLowLatencyMode="Enable TCP pacing" +Basic.Settings.Advanced.Network.TCPPacing.Tooltip="Attempts to make RTMP output friendlier to other latency sensitive applications on the network by regulating the rate of transmission.\nIt may increase the risk of dropped frames on unstable connections." +Basic.Settings.Advanced.Hotkeys.HotkeyFocusBehavior="Hotkey Focus Behaviour" +Basic.Settings.Advanced.Hotkeys.NeverDisableHotkeys="Never disable hotkeys" +Basic.Settings.Advanced.Hotkeys.DisableHotkeysInFocus="Disable hotkeys when main window is in focus" +Basic.Settings.Advanced.Hotkeys.DisableHotkeysOutOfFocus="Disable hotkeys when main window is not in focus" +Basic.Settings.Advanced.AutoRemux="Automatically remux to mp4" +Basic.Settings.Advanced.AutoRemux.MP4="(record as mkv)" +Basic.AdvAudio="Advanced Audio Properties" +Basic.AdvAudio.ActiveOnly="Active Sources Only" +Basic.AdvAudio.Name="Name" +Basic.AdvAudio.Volume="Volume" +Basic.AdvAudio.VolumeSource="Volume for '%1'" +Basic.AdvAudio.Mono="Mono" +Basic.AdvAudio.MonoSource="Mono Downmix for '%1'" +Basic.AdvAudio.Balance="Balance" +Basic.AdvAudio.BalanceSource="Balance for '%1'" +Basic.AdvAudio.SyncOffset="Sync Offset" +Basic.AdvAudio.SyncOffsetSource="Sync Offset for '%1'" +Basic.AdvAudio.Monitoring="Audio Monitoring" +Basic.AdvAudio.Monitoring.None="Monitor Off" +Basic.AdvAudio.Monitoring.MonitorOnly="Monitor Only (mute output)" +Basic.AdvAudio.Monitoring.Both="Monitor and Output" +Basic.AdvAudio.MonitoringSource="Audio Monitoring for '%1'" +Basic.AdvAudio.AudioTracks="Tracks" +Basic.Settings.Hotkeys="Hotkeys" +Basic.Settings.Hotkeys.Pair="Key combinations shared with '%1' act as toggles" +Basic.Settings.Hotkeys.Filter="Filter" +Basic.Hotkeys.SelectScene="Switch to scene" +Basic.SystemTray.Show="Show" +Basic.SystemTray.Hide="Hide" +Basic.SystemTray.Message.Reconnecting="Disconnected. 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="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" +Hotkeys.Escape="Esc" +Mute="Mute" +Unmute="Unmute" +Push-to-mute="Push-to-mute" +Push-to-talk="Push-to-talk" +SceneItemShow="Show '%1'" +SceneItemHide="Hide '%1'" +OutputWarnings.NoTracksSelected="You must select at least one track" OutputWarnings.MP4Recording="Warning: Recordings saved to MP4/MOV will be unrecoverable if the file cannot be finalised (e.g. as a result of BSODs, power losses, etc.). If you want to record multiple audio tracks consider using MKV and remux the recording to MP4/MOV after it is finished (File → Remux Recordings)" +OutputWarnings.CannotPause="Warning: Recordings cannot be paused if the recording encoder is set to \"(Use stream encoder)\"" +FinalScene.Title="Delete Scene" +FinalScene.Text="There needs to be at least one scene." +NoSources.Title="No Sources" +NoSources.Text="It looks like you haven't added any video sources yet, so you will only be outputting a blank screen. Are you sure you want to do this?" +NoSources.Text.AddSource="You can add sources by clicking the + icon under the Sources box in the main window at any time." +NoSources.Label="You don't have any sources.\nClick the + button below,\nor right click here to add one." ChangeBG="Set Colour" CustomColor="Custom Colour" +BrowserSource.EnableHardwareAcceleration="Enable Browser Source Hardware Acceleration" +About="About" +About.Info="OBS Studio is a free and open source video recording and live streaming software." +About.Donate="Make a Contribution" +About.GetInvolved="Get Involved" +About.Authors="Authors" About.License="Licence" +About.Contribute="Support the OBS Project" + +AddUrl.Title="Add Source via URL" +AddUrl.Text="You have dragged a URL into OBS. This will automatically add the link as a source. Continue?" +AddUrl.Text.Url="URL: %1" + +ResizeOutputSizeOfSource="Resize output (source size)" +ResizeOutputSizeOfSource.Text="The base and output resolutions will be resized to the size of the current source." +ResizeOutputSizeOfSource.Continue="Do you want to continue?" + +PreviewTransition="Preview Transition" + +Importer="Scene Collection Importer" +Importer.SelectCollection="Select a Scene Collection" +Importer.Collection="Scene Collection" +Importer.HelpText="Add files to this window to import collections from OBS or other supported programs." +Importer.Path="Collection Path" +Importer.Program="Detected Application" +Importer.AutomaticCollectionPrompt="Automatically Search for Scene Collections" +Importer.AutomaticCollectionText="OBS can automatically find importable scene collections from supported third-party programs. Would you like OBS to automatically find collections for you?\n\nYou can change this later in Settings > General > Importers." +Restart="Restart" +NeedsRestart="OBS Studio needs to be restarted. Do you want to restart now?" +ContextBar.NoSelectedSource="No source selected" +ContextBar.ResetTransform="Reset Transform" +ContextBar.FitToCanvas="Fit to Canvas" - - - - +ContextBar.MediaControls.PlayMedia="Play Media" +ContextBar.MediaControls.PauseMedia="Pause Media" +ContextBar.MediaControls.StopMedia="Stop Media" +ContextBar.MediaControls.RestartMedia="Restart Media" +ContextBar.MediaControls.PlaylistNext="Next in Playlist" +ContextBar.MediaControls.PlaylistPrevious="Previous in Playlist" +ContextBar.MediaControls.MediaProperties="Media Properties" +ContextBar.MediaControls.BlindSeek="Media Seek Widget" diff --git a/UI/data/locale/en-US.ini b/UI/data/locale/en-US.ini index eb31c66..09205f7 100644 --- a/UI/data/locale/en-US.ini +++ b/UI/data/locale/en-US.ini @@ -174,6 +174,7 @@ Basic.AutoConfig.StreamPage.DisconnectAccount="Disconnect Account" Basic.AutoConfig.StreamPage.DisconnectAccount.Confirm.Title="Disconnect Account?" Basic.AutoConfig.StreamPage.DisconnectAccount.Confirm.Text="This change will apply immediately. Are you sure you want to disconnect your account?" Basic.AutoConfig.StreamPage.GetStreamKey="Get Stream Key" +Basic.AutoConfig.StreamPage.MoreInfo="More Info" Basic.AutoConfig.StreamPage.UseStreamKey="Use Stream Key" Basic.AutoConfig.StreamPage.Service="Service" Basic.AutoConfig.StreamPage.Service.ShowAll="Show All..." @@ -407,8 +408,8 @@ Deinterlacing.TopFieldFirst="Top Field First" Deinterlacing.BottomFieldFirst="Bottom Field First" # volume control accessibility text -VolControl.SliderUnmuted="Volume slider for '%1': %2" -VolControl.SliderMuted="Volume slider for '%1': %2 (currently muted)" +VolControl.SliderUnmuted="Volume slider for '%1':" +VolControl.SliderMuted="Volume slider for '%1': (currently muted)" VolControl.Mute="Mute '%1'" VolControl.Properties="Properties for '%1'" @@ -429,6 +430,7 @@ Basic.Main.RenameSceneCollection.Title="Rename Scene Collection" # add profile dialog AddProfile.Title="Add Profile" AddProfile.Text="Please enter the name of the profile" +AddProfile.WizardCheckbox="Show auto-configuration wizard" # rename profile dialog RenameProfile.Title="Rename Profile" @@ -447,6 +449,12 @@ Basic.SourceSelect.CreateNew="Create new" Basic.SourceSelect.AddExisting="Add Existing" Basic.SourceSelect.AddVisible="Make source visible" +# source box +Basic.Main.Sources.Visibility="Visibility" +Basic.Main.Sources.VisibilityDescription="Controls the visibility of '%1' in the canvas" +Basic.Main.Sources.Lock="Lock" +Basic.Main.Sources.LockDescription="Locks the position and scale of '%1' in the canvas" + # properties window Basic.PropertiesWindow="Properties for '%1'" Basic.PropertiesWindow.AutoSelectFormat="%1 (autoselect: %2)" @@ -705,6 +713,13 @@ Basic.Settings.Stream.StreamSettingsWarning="Open Settings" Basic.Settings.Stream.MissingUrlAndApiKey="URL and Stream Key are missing.\n\nOpen settings to enter the URL and Stream Key in the 'stream' tab." Basic.Settings.Stream.MissingUrl="Stream URL is missing.\n\nOpen settings to enter the URL in the 'Stream' tab." Basic.Settings.Stream.MissingStreamKey="Stream key is missing.\n\nOpen settings to enter the stream key in the 'Stream' tab." +Basic.Settings.Stream.IgnoreRecommended="Ignore streaming service setting recommendations" +Basic.Settings.Stream.IgnoreRecommended.Warn.Title="Override Recommended Settings" +Basic.Settings.Stream.IgnoreRecommended.Warn.Text="Warning: Ignoring the service's limitations may result in degraded stream quality or prevent you from streaming.\n\nContinue?" +Basic.Settings.Stream.Recommended.MaxVideoBitrate="Maximum Video Bitrate: %1 kbps" +Basic.Settings.Stream.Recommended.MaxAudioBitrate="Maximum Audio Bitrate: %1 kbps" +Basic.Settings.Stream.Recommended.MaxResolution="Maximum Resolution: %1" +Basic.Settings.Stream.Recommended.MaxFPS="Maximum FPS: %1" # basic mode 'output' settings Basic.Settings.Output="Output" @@ -712,7 +727,6 @@ Basic.Settings.Output.Format="Recording Format" Basic.Settings.Output.Encoder="Encoder" Basic.Settings.Output.SelectDirectory="Select Recording Directory" Basic.Settings.Output.SelectFile="Select Recording File" -Basic.Settings.Output.EnforceBitrate="Enforce streaming service bitrate limits" Basic.Settings.Output.DynamicBitrate="Dynamically change bitrate to manage congestion" Basic.Settings.Output.DynamicBitrate.Beta="Dynamically change bitrate to manage congestion (Beta)" Basic.Settings.Output.DynamicBitrate.TT="Instead of dropping frames to reduce congestion, dynamically changes bitrate on the fly.\n\nNote that this can increase delay to viewers if there is significant sudden congestion.\nWhen the bitrate drops, it can take up to a few minutes to restore.\n\nCurrently only supported for RTMP." @@ -733,8 +747,8 @@ Basic.Settings.Output.Simple.RecordingQuality.Stream="Same as stream" Basic.Settings.Output.Simple.RecordingQuality.Small="High Quality, Medium File Size" Basic.Settings.Output.Simple.RecordingQuality.HQ="Indistinguishable Quality, Large File Size" Basic.Settings.Output.Simple.RecordingQuality.Lossless="Lossless Quality, Tremendously Large File Size" -Basic.Settings.Output.Simple.Warn.VideoBitrate="Warning: The streaming video bitrate will be set to %1, which is the upper limit for the current streaming service. If you're sure you want to go above %1, enable advanced encoder options and uncheck \"Enforce streaming service bitrate limits\"." -Basic.Settings.Output.Simple.Warn.AudioBitrate="Warning: The streaming audio bitrate will be set to %1, which is the upper limit for the current streaming service. If you're sure you want to go above %1, enable advanced encoder options and uncheck \"Enforce streaming service bitrate limits\"." +Basic.Settings.Output.Simple.Warn.VideoBitrate="Warning: The streaming video bitrate will be set to %1, which is the upper limit for the current streaming service." +Basic.Settings.Output.Simple.Warn.AudioBitrate="Warning: The streaming audio bitrate will be set to %1, which is the upper limit for the current streaming service." Basic.Settings.Output.Simple.Warn.CannotPause="Warning: Recordings cannot be paused if the recording quality is set to \"Same as stream\"." Basic.Settings.Output.Simple.Warn.Encoder="Warning: Recording with a software encoder at a different quality than the stream will require extra CPU usage if you stream and record at the same time." Basic.Settings.Output.Simple.Warn.Lossless="Warning: Lossless quality generates tremendously large file sizes! Lossless quality can use upward of 7 gigabytes of disk space per minute at high resolutions and framerates. Lossless is not recommended for long recordings unless you have a very large amount of disk space available." @@ -745,6 +759,11 @@ 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.Simple.TwitchVodTrack="Twitch VOD Track (Uses Track 2)" +Basic.Settings.Output.Warn.EnforceResolutionFPS.Title="Incompatible Resolution/Framerate" +Basic.Settings.Output.Warn.EnforceResolutionFPS.Msg="This streaming service does not support your current output resolution and/or framerate. They will be changed to the closest compatible value:\n\n%1\n\nDo you want to continue?" +Basic.Settings.Output.Warn.EnforceResolutionFPS.Resolution="Resolution: %1" +Basic.Settings.Output.Warn.EnforceResolutionFPS.FPS="FPS: %1" Basic.Settings.Output.VideoBitrate="Video Bitrate" Basic.Settings.Output.AudioBitrate="Audio Bitrate" Basic.Settings.Output.Reconnect="Automatically Reconnect" @@ -760,16 +779,17 @@ Basic.Settings.Output.NoSpaceFileName="Generate File Name without Space" Basic.Settings.Output.Adv.Rescale="Rescale Output" Basic.Settings.Output.Adv.AudioTrack="Audio Track" Basic.Settings.Output.Adv.Streaming="Streaming" -Basic.Settings.Output.Adv.ApplyServiceSettings="Enforce streaming service encoder settings" Basic.Settings.Output.Adv.Audio.Track1="Track 1" Basic.Settings.Output.Adv.Audio.Track2="Track 2" Basic.Settings.Output.Adv.Audio.Track3="Track 3" Basic.Settings.Output.Adv.Audio.Track4="Track 4" Basic.Settings.Output.Adv.Audio.Track5="Track 5" Basic.Settings.Output.Adv.Audio.Track6="Track 6" +Basic.Settings.Output.Adv.TwitchVodTrack="Twitch VOD Track" # basic mode 'output' settings - advanced section - recording subsection Basic.Settings.Output.Adv.Recording="Recording" +Basic.Settings.Output.Adv.Recording.RecType="Recording Type" Basic.Settings.Output.Adv.Recording.Type="Type" Basic.Settings.Output.Adv.Recording.Type.Standard="Standard" Basic.Settings.Output.Adv.Recording.Type.FFmpegOutput="Custom Output (FFmpeg)" @@ -905,13 +925,18 @@ Basic.AdvAudio="Advanced Audio Properties" Basic.AdvAudio.ActiveOnly="Active Sources Only" Basic.AdvAudio.Name="Name" Basic.AdvAudio.Volume="Volume" +Basic.AdvAudio.VolumeSource="Volume for '%1'" Basic.AdvAudio.Mono="Mono" +Basic.AdvAudio.MonoSource="Mono Downmix for '%1'" Basic.AdvAudio.Balance="Balance" +Basic.AdvAudio.BalanceSource="Balance for '%1'" Basic.AdvAudio.SyncOffset="Sync Offset" +Basic.AdvAudio.SyncOffsetSource="Sync Offset for '%1'" Basic.AdvAudio.Monitoring="Audio Monitoring" Basic.AdvAudio.Monitoring.None="Monitor Off" Basic.AdvAudio.Monitoring.MonitorOnly="Monitor Only (mute output)" Basic.AdvAudio.Monitoring.Both="Monitor and Output" +Basic.AdvAudio.MonitoringSource="Audio Monitoring for '%1'" Basic.AdvAudio.AudioTracks="Tracks" # basic mode 'hotkeys' settings diff --git a/UI/data/locale/eo-UY.ini b/UI/data/locale/eo-UY.ini new file mode 100644 index 0000000..1f07a7e --- /dev/null +++ b/UI/data/locale/eo-UY.ini @@ -0,0 +1,324 @@ + +Language="Esperanto" + +OK="Bone" +Apply="Apliki" +Cancel="Nuligi" +Close="Fermi" +Save="Konservi" +Discard="Forĵeti" +Disable="Malebligi" +Yes="Jes" +No="Ne" +Add="Aldoni" +Remove="Forigi" +Rename="Renomi" +Interact="Interagi" +Filters="Filtriloj" +Properties="Ecoj" +MoveUp="Movi supren" +MoveDown="Movi malsupren" +Settings="Agordoj" +Display="Ekrano" +Name="Nomo" +Exit="Eliri" +Mixer="Sonmiksilo" +Browse="Foliumi" +Mono="Monofonia" +Stereo="Stereofonia" +DroppedFrames="Perditaj kadroj %1 (%2%)" +StudioProgramProjector="Plenekrana projekciilo (programaro)" +PreviewProjector="Plenekrana projekciilo (antaŭvido)" +SceneProjector="Plenekrana projekciilo (sceno)" +SourceProjector="Plenekrana projekciilo (fonto)" +StudioProgramWindow="Fenestra projekciilo (programaro)" +PreviewWindow="Fenestra projekciilo (antaŭvido)" +SceneWindow="Fenestra projekciilo (sceno)" +SourceWindow="Fenestra projekciilo (fonto)" +MultiviewProjector="Multvido (plenekrana)" +MultiviewWindowed="Multvido (fenestra)" +ResizeProjectorWindowToContent="Mezurigi fenestron laŭ enhavo" +Clear="Viŝi" +Revert="Malfari" +Show="Montri" +Hide="Kaŝi" +UnhideAll="Malkaŝi ĉiujn" +Untitled="Sentitola" +New="Nova" +Duplicate="Duobligi" +Enable="Ebligi" +DisableOSXVSync="Malebligi v-sinkon de macOS" +ResetOSXVSyncOnExit="Restarigi v-sinkon de macOS je eliro" +HighResourceUsage="Kodado troŝarĝita! Konsideru malpliigi video-agordojn aŭ uzi pli rapidan kodado-antaŭagordon." +Transition="Transpaso" +QuickTransitions="Rapidaj transpasoj" +FadeToBlack="Dissolvi al nigro" +Left="Maldekstre" +Right="Dekstre" +Top="Supre" +Bottom="Malsupre" +Reset="Restarigi" +Hours="Horoj" +Minutes="Minutoj" +Seconds="Sekundoj" +Deprecated="Evitindaj" +ReplayBuffer="Reluda bufro" +Import="Importi" +Export="Eksporti" +Copy="Kopii" +Paste="Alglui" +PasteReference="Alglui (referenco)" +PasteDuplicate="Alglui (duobligi)" +RemuxRecordings="Konverti registraĵojn" +Next="Sekve" +Back="Antaŭe" +Defaults="Defaŭltoj" +HideMixer="Malkaŝi en miksilo" +TransitionOverride="Devigi transpason" +None="Neniu" +StudioMode.Preview="Antaŭvido" +StudioMode.Program="Programaro" +ShowInMultiview="Montri en multivido" +VerticalLayout="Vertikala aranĝo" +Group="Grupo" +DoNotShowAgain="Ne montru denove" +Default="(Defaŭlta)" +Calculating="Kalkulado..." +Fullscreen="Plenekrano" +Windowed="En fenestro" +Percent="Procento" +RefreshBrowser="Aktualigi" +AspectRatio="Ekranformato %1:%2" +LockVolume="Ŝlosi laŭtecon" +LogViewer="Vidilo de protokoloj" +ShowOnStartup="Montri je lanĉo" +OpenFile="Malfermi dosieron" +AddValue="Aldoni %1" + +AlreadyRunning.Title="OBS jam ruliĝas" +AlreadyRunning.Text="OBS estas jam ruliĝanta! Krom se vi intencis fari tion, bonvolu fermi ajnajn ekzistantajn aperojn de OBS antaŭ ol provi ruli novan. Se vi agordis OBS por plejetiĝi al la taskopleto, bonvolu kontroli ĉu ĝi ankoraŭ ruliĝas tie." +AlreadyRunning.LaunchAnyway="Lanĉi ĉiuokaze" + +ChromeOS.Title="Nesubtenata platformo" +ChromeOS.Text="OBS ŝajnas ruliĝi ene de entenilo de ChromeOS. Tiu ĉi platformo estas nesubtenata" + +DockCloseWarning.Title="Fermado de dokebla fenestro" +DockCloseWarning.Text="Vi ĵus fermis dokeblan fenestron. Se vi volas ĝin remontrigi, uzu la menuon Vido → Dokoj sur la menustrio." + +ExtraBrowsers="Laŭmendaj esploril-dokoj" +ExtraBrowsers.Info="Aldonu dokojn per doni al ili nomon kaj retadreso, kaj tiam alklaku Apliki aŭ Fermi por malfermi la dokojn. Vi povas aldoni aŭ forigi dokojn iam ajn." +ExtraBrowsers.DockName="Dok-nomo" + +Auth.Authing.Title="Aŭtentigado..." +Auth.Authing.Text="Aŭtentigado per %1, bonvole atendu..." +Auth.AuthFailure.Title="Malsukceso de aŭtentigo" +Auth.AuthFailure.Text="Malsukcesis aŭtentigi per %1:\n\n%2: %3" +Auth.InvalidScope.Title="Aŭtentigo deviga" +Auth.InvalidScope.Text="La aŭtentigaj postuloj por %1 ŝanĝiĝis. Iuj trajtoj eble ne disponeblas." +Auth.LoadingChannel.Title="Ŝargado de kanal-informoj..." +Auth.LoadingChannel.Text="Ŝargado de kanal-informoj por %1, bonvole atendu..." +Auth.ChannelFailure.Title="Malsukcesis ŝargi kanalon" +Auth.ChannelFailure.Text="Malsukcesis ŝargi kanal-informojn por %1\n\n%2: %3" +Auth.Chat="Babilejo" +Auth.StreamInfo="Elsend-informoj" +TwitchAuth.Stats="Statistikoj de Twitch" +TwitchAuth.Feed="Aktivec-fluo de Twitch" +TwitchAuth.TwoFactorFail.Title="Ne povis informpeti elsend-ŝlosilon" +TwitchAuth.TwoFactorFail.Text="OBS ne povis konekti al via Twitch-konto. Bonvolu certigi ke dufaktora aŭtentigo estas agordita en viaj agordoj de sekureco en Twitch, pro ke tio estas necesa por elsendi." +RestreamAuth.Channels="Kanaloj de Restream" + +Copy.Filters="Kopii filtrilojn" +Paste.Filters="Alglui filtrilojn" + +BrowserPanelInit.Title="Pravalorizado de esplorilo..." +BrowserPanelInit.Text="Pravalorizado de esplorilo, bonvole atendu..." + +BandwidthTest.Region="Regiono" +BandwidthTest.Region.US="Usono" +BandwidthTest.Region.EU="Eŭropo" +BandwidthTest.Region.Asia="Azio" +BandwidthTest.Region.Other="Alia" + +Basic.AutoConfig="Aŭtomata agordilo" +Basic.AutoConfig.ApplySettings="Apliki agordojn" +Basic.AutoConfig.StartPage="Informoj pri uzado" +Basic.AutoConfig.StartPage.SubTitle="Indiku por kio vi volas uzi la programaron" +Basic.AutoConfig.StartPage.PrioritizeStreaming="Optimumigu por elsendado, registrado estas akcesora" +Basic.AutoConfig.StartPage.PrioritizeRecording="Optimumigi nur por registrado, mi ne elsendos" +Basic.AutoConfig.StartPage.PrioritizeVirtualCam="Mi nur uzos la virtualan kameraon" +Basic.AutoConfig.VideoPage="Video-agordoj" +Basic.AutoConfig.VideoPage.SubTitle="Indiku la video-agordojn, kiujn vi volas uzi" +Basic.AutoConfig.VideoPage.BaseResolution.UseCurrent="Uzi aktualan (%1x%2)" +Basic.AutoConfig.VideoPage.BaseResolution.Display="Ekrano %1 (%2x%3)" +Basic.AutoConfig.VideoPage.FPS.UseCurrent="Uzi aktualan (%1)" +Basic.AutoConfig.VideoPage.FPS.PreferHighFPS="Aŭ 60 aŭ 30, sed preferu 60 kiam eblas" +Basic.AutoConfig.VideoPage.FPS.PreferHighRes="Aŭ 60 aŭ 30, sed preferu altan distingivon" +Basic.AutoConfig.VideoPage.CanvasExplanation="Notu: La kanvasa (baza) distingivo ne necese samas kiel la distingivo per kiu vi elsendos aŭ registros. Via efektiva distingivo de elsendado/registrado eble reduktiĝos de la kanvasa distingivo por malpliigi rimed-uzadon aŭ bitrapidaj postuloj." +Basic.AutoConfig.StreamPage="Elsend-informoj" +Basic.AutoConfig.StreamPage.SubTitle="Bonvole enigi viajn elsend-informojn" +Basic.AutoConfig.StreamPage.ConnectAccount="Konekti konton (rekomendite)" +Basic.AutoConfig.StreamPage.DisconnectAccount="Malkonekti konton" +Basic.AutoConfig.StreamPage.DisconnectAccount.Confirm.Title="Ĉu malkonektu konton?" +Basic.AutoConfig.StreamPage.DisconnectAccount.Confirm.Text="Tiu ĉi ŝanĝo aplikiĝos tuj. Ĉu vi certas, ke vi volas malkonekti vian konton?" +Basic.AutoConfig.StreamPage.GetStreamKey="Akiri elsend-ŝlosilon" +Basic.AutoConfig.StreamPage.MoreInfo="Pli da informoj" +Basic.AutoConfig.StreamPage.UseStreamKey="Uzi elsend-ŝlosilon" +Basic.AutoConfig.StreamPage.Service="Servo" +Basic.AutoConfig.StreamPage.Service.ShowAll="Montri ĉiujn..." +Basic.AutoConfig.StreamPage.Service.Custom="Laŭmenda..." +Basic.AutoConfig.StreamPage.Server="Servilo" +Basic.AutoConfig.StreamPage.StreamKey="Elsend-ŝlosilo" +Basic.AutoConfig.StreamPage.StreamKey.LinkToSite="(ligilo)" +Basic.AutoConfig.StreamPage.PerformBandwidthTest="Taksi bitrapidon per kapacita testo (eble necesos kelkaj minutoj)" + + + +Updater.Skip="Preterpasi version" +Updater.Running.Title="Programaro aktuale aktiva" +Updater.Running.Text="Eligoj estas aktuale aktivaj, bonvolu fermi ajnajn aktivajn eligojn antaŭ ol provi ĝisdatigi" +Updater.NoUpdatesAvailable.Title="Neniuj ĝisdatigoj disponeblas" +Updater.NoUpdatesAvailable.Text="Neniuj ĝisdatigoj estas nuntempe disponeblaj" +Updater.FailedToLaunch="Malsukcesis lanĉi ĝisdatigilon" +Updater.GameCaptureActive.Title="Ludkaptado aktiva" +Updater.GameCaptureActive.Text="La ludkapta hok-biblioteko estas aktuale uzata. Bonvolu fermi ajnajn ludojn/programarojn kaptatajn (aŭ restartigu Windows) kaj reprovu." + +QuickTransitions.SwapScenes="Interŝanĝi antaŭvidan/eligan scenojn post transpasi" +QuickTransitions.SwapScenesTT="Interŝanĝas la antaŭvidan kaj eligan scenojn post transpasi (se la originala sceno de la eligo ankoraŭ ekzistas).\nTio ne malfaros ajnajn ŝanĝojn, kiuj eble fariĝis al la originala sceno de la eligo." +QuickTransitions.DuplicateScene="Duobligi scenon" +QuickTransitions.DuplicateSceneTT="Dum redaktado de la sama sceno, permesas redakti transformon/videblecon de fontoj sen modifi la eligon.\nPor redakti ecoj de fontoj sen modifi la eligon, ebligu 'Duobligi fontojn'.\nŜanĝi tiun ĉi valuton restarigos la aktualan elig-scenon (se ĝi ankoraŭ ekzistas)." +QuickTransitions.EditProperties="Duobligi fontojn" +QuickTransitions.EditPropertiesTT="Dum redaktado de la sama sceno, permesas redakti ecojn de fontoj sen modifi la eligon.\nTio ĉi nur uzeblas se 'Duobligi scenon' estas ebligita.\nIuj fontoj (kiel kaptaj aŭ aŭdvidaĵaj fontoj) ne subtenas tion ĉi kaj ne povas redaktiĝi aparte.\nŜanĝi tiun ĉi valuton restarigos la aktualan elig-scenon (se ĝi ankoraŭ ekzistas).\n\nAverto: Pro ke fontoj duobliĝos, tio ĉi eble necesigas ekstrajn sistem- aŭ video-rimedojn." +QuickTransitions.HotkeyName="Rapida transpaso: %1" + +Basic.AddTransition="Aldoni agordeblan transpason" +Basic.RemoveTransition="Forigi agordeblan transpason" +Basic.TransitionProperties="Ecoj de transpaso" +Basic.SceneTransitions="Scen-transpasoj" +Basic.TransitionDuration="Daŭro" +Basic.TogglePreviewProgramMode="Studio-reĝimo" + +TransitionNameDlg.Text="Bonvolu enigi la nomon de la transpaso" +TransitionNameDlg.Title="Nomo de transpaso" + +TitleBar.Profile="Agordaro" +TitleBar.Scenes="Scenoj" + +NameExists.Title="Nomo jam ekzistas" +NameExists.Text="La nomo jam estas uzata." + +NoNameEntered.Title="Bonvolu enigi validan nomon" +NoNameEntered.Text="La nomo estas deviga." + +ConfirmStart.Title="Ĉu komenci elsendon?" +ConfirmStart.Text="Ĉu vi certas, ke vi volas komenci la elsendon?" + +ConfirmStop.Title="Ĉu ĉesigi elsendon?" +ConfirmStop.Text="Ĉu vi certas ke vi volas ĉesigi la elsendon?" + +ConfirmStopRecord.Title="Ĉu ĉesigi registradon?" +ConfirmStopRecord.Text="Ĉu vi certas ke vi volas ĉesigi la registradon?" + +ConfirmBWTest.Title="Ĉu komenci kapacitan teston?" +ConfirmBWTest.Text="Vi havas OBS agorditan en reĝimo de kapacita testo. Tiu ĉi reĝimo ebligas ret-testadon sen vere tujelsendi. Kiam vi finiĝas pri testado, vi devos malebligi ĝin por ke spektantoj povu vidi vian elsendon.\n\nĈu vi volas daŭrigi?" + +ConfirmExit.Title="Ĉu eliri OBS?" +ConfirmExit.Text="OBS estas aktuale aktiva. Ĉiuj elsendoj/registradoj fermiĝos. Ĉu vi vere volas eliri?" + +ConfirmRemove.Title="Konfirmado de forigo" +ConfirmRemove.Text="Ĉu vi vere volas forigi '$1'?" +ConfirmRemove.TextMultiple="Ĉu vi vere volas forigi %1 erojn?" + +Output.StartStreamFailed="Malsukcesis ekelsendi" +Output.StartRecordingFailed="Malsukcesis ekregistri" +Output.StartReplayFailed="Malsukcesis komenci reludan bufron" +Output.StartFailedGeneric="Komencado de la eligo malsukcesis. Bonvolu kontroli la protokolon por detaloj.\n\nNotu: Se vi uzas la kodiloj NVENC aŭ AMD, certigu ke viaj videopeliloj estas ĝisdataj." + +Output.ReplayBuffer.PauseWarning.Title="Ne povas konservi reludojn dum paŭzo" +Output.ReplayBuffer.PauseWarning.Text="Averto: Reludoj ne konserveblas dum registrado estas paŭzigita." + +Output.ConnectFail.Title="Malsukcesis konekti" +Output.ConnectFail.BadPath="Nevalida indiko aŭ konekt-retadreso. Bonvole kontrolu viajn agordojn por certigi, ke ili validas." + + + + + + + + + + + +ScaleFiltering="Skal-filtrado" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Basic.Settings.Stream.IgnoreRecommended="Malatenti rekomendojn de elsend-servaj agordoj" +Basic.Settings.Stream.IgnoreRecommended.Warn.Title="Transpasi rekomenditajn agordojn" +Basic.Settings.Stream.IgnoreRecommended.Warn.Text="Averto: Malatenti la limojn de la servo eble rezultos en malaltigita elsend-kvalito aŭ preventos vin de elsendi.\n\nĈu daŭrigi?" +Basic.Settings.Stream.Recommended.MaxVideoBitrate="Maksimuma video-bitrapido: %1 kbps" +Basic.Settings.Stream.Recommended.MaxAudioBitrate="Maksimuma son-bitrapido: %1 kbps" + +Basic.Settings.Output.Simple.Warn.VideoBitrate="Averto: La elsenda video-bitrapido agordiĝos al %1, kio estas la supra limo por la aktuala elsend-servo." +Basic.Settings.Output.Simple.Warn.AudioBitrate="Averto: La elsenda son-bitrapido agordiĝos al %1, kio estas la supra limo por la aktuala elsend-servo." + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/UI/data/locale/es-ES.ini b/UI/data/locale/es-ES.ini index 9be15e4..07b2556 100644 --- a/UI/data/locale/es-ES.ini +++ b/UI/data/locale/es-ES.ini @@ -93,7 +93,7 @@ LockVolume="Bloquear volumen" LogViewer="Visor de registros" ShowOnStartup="Mostrar al inicio" OpenFile="Abrir archivo" -AddValue="Añadir %1" +AddValue="Agregar %1" AlreadyRunning.Title="OBS ya se está ejecutando" AlreadyRunning.Text="¡OBS ya se está ejecutando! A no ser que quieras hacer esto, por favor, cierra todas las ventanas de OBS antes de intentar iniciar una nueva. Si tienes configurado OBS para que se minimice a la barra de tareas, comprueba si sigue ejecutándose ahí." @@ -161,6 +161,7 @@ Basic.AutoConfig.StreamPage.DisconnectAccount="Desconectar cuenta" Basic.AutoConfig.StreamPage.DisconnectAccount.Confirm.Title="¿Desconectar cuenta?" Basic.AutoConfig.StreamPage.DisconnectAccount.Confirm.Text="Este cambio se aplicará inmediatamente. ¿Está seguro de que desea desconectar su cuenta?" Basic.AutoConfig.StreamPage.GetStreamKey="Obtener clave de transmisión" +Basic.AutoConfig.StreamPage.MoreInfo="Más información" Basic.AutoConfig.StreamPage.UseStreamKey="Usar clave de emisión" Basic.AutoConfig.StreamPage.Service="Servicio" Basic.AutoConfig.StreamPage.Service.ShowAll="Mostrar todos..." @@ -365,8 +366,8 @@ Deinterlacing.Yadif2x="Yadif 2x" Deinterlacing.TopFieldFirst="Campo Superior Primero" Deinterlacing.BottomFieldFirst="Campo Inferior Primero" -VolControl.SliderUnmuted="Deslizador de volumen para '%1': %2" -VolControl.SliderMuted="Deslizador de volumen para '%1': %2 (silenciado)" +VolControl.SliderUnmuted="Deslizador de volumen para '%1':" +VolControl.SliderMuted="Deslizador de volumen para '%1': (actualmente silenciado)" VolControl.Mute="Silenciar '%1'" VolControl.Properties="Propiedades para '%1'" @@ -382,6 +383,7 @@ Basic.Main.RenameSceneCollection.Title="Cambiar el nombre de colección de escen AddProfile.Title="Añadir perfil" AddProfile.Text="Escriba el nombre del perfil" +AddProfile.WizardCheckbox="Mostrar el asistente de configuración automática" RenameProfile.Title="Renombrar perfil" @@ -396,6 +398,11 @@ Basic.SourceSelect.CreateNew="Crear nuevo" Basic.SourceSelect.AddExisting="Añadir existentes" Basic.SourceSelect.AddVisible="Hacer visible la fuente" +Basic.Main.Sources.Visibility="Visibilidad" +Basic.Main.Sources.VisibilityDescription="Controla la visibilidad de '%1' en el lienzo" +Basic.Main.Sources.Lock="Bloquear" +Basic.Main.Sources.LockDescription="Bloquea la posición y la escala de '%1' en el lienzo" + Basic.PropertiesWindow="Propiedades para '%1'" Basic.PropertiesWindow.AutoSelectFormat="%1 (seleccionar: %2)" Basic.PropertiesWindow.SelectColor="Seleccionar color" @@ -635,13 +642,19 @@ Basic.Settings.Stream.StreamSettingsWarning="Abrir Ajustes" Basic.Settings.Stream.MissingUrlAndApiKey="Falta la URL y clave de retransmisión.\n\nAbre los ajustes para introducir la URL y la clave de retransmisión en la pestaña 'Emisión'." Basic.Settings.Stream.MissingUrl="Falta la URL del stream.\n\nAbre la configuración para introducir la URL en la pestaña 'Emisión'." Basic.Settings.Stream.MissingStreamKey="Falta la clave de retransmisión.\n\nAbre los ajustes para introducir la clave de retransmisión en la pestaña 'Emisión'." +Basic.Settings.Stream.IgnoreRecommended="Ignorar las recomendaciones de configuración del servicio de streaming" +Basic.Settings.Stream.IgnoreRecommended.Warn.Title="Anular los ajustes recomendados" +Basic.Settings.Stream.IgnoreRecommended.Warn.Text="Advertencia: Ignorar las limitaciones del servicio puede provocar una degradación en la calidad del stream o impedir que se emita.\n\n¿Continuar?" +Basic.Settings.Stream.Recommended.MaxVideoBitrate="Máxima tasa de bits de vídeo: %1 kbps" +Basic.Settings.Stream.Recommended.MaxAudioBitrate="Máxima tasa de bits de audio: %1 kbps" +Basic.Settings.Stream.Recommended.MaxResolution="Resolución máxima: %1" +Basic.Settings.Stream.Recommended.MaxFPS="Tasa máxima de fotogramas: %1" Basic.Settings.Output="Salida" Basic.Settings.Output.Format="Formato de grabación" Basic.Settings.Output.Encoder="Codificador" Basic.Settings.Output.SelectDirectory="Seleccione Directorio de grabación" Basic.Settings.Output.SelectFile="Seleccione archivo de grabación" -Basic.Settings.Output.EnforceBitrate="Aplicar los límites de bitrate del servicio de streaming" Basic.Settings.Output.DynamicBitrate="Cambia dinámicamente la tasa de bits para gestionar la congestión" Basic.Settings.Output.DynamicBitrate.Beta="Cambia dinámicamente la tasa de bits para gestionar la congestión (Beta)" Basic.Settings.Output.DynamicBitrate.TT="En lugar de saltar fotogramas para reducir la congestión, cambia dinámicamente el bitrate sobre la marcha.\n\nTen en cuenta que esto puede aumentar el retardo de la transmisión si hay una congestión repentina significativa.\nCuando el bitrate baja, puede tardar unos minutos en restaurarse.\n\nActualmente sólo es compatible con RTMP." @@ -662,8 +675,8 @@ Basic.Settings.Output.Simple.RecordingQuality.Stream="Igual a la emisión" Basic.Settings.Output.Simple.RecordingQuality.Small="Alta calidad, tamaño de archivo medio" Basic.Settings.Output.Simple.RecordingQuality.HQ="Tamaño de archivo grande, calidad indistinguible" Basic.Settings.Output.Simple.RecordingQuality.Lossless="Tamaño del archivo sin pérdida de calidad, tremendamente grande" -Basic.Settings.Output.Simple.Warn.VideoBitrate="ADVERTENCIA: El streaming de vídeo se establecerá a %1, que es el límite superior para el servicio de streaming actual. Si estás seguro que quieres ir por encima de %1, active las opciones avanzadas del codificador y desactive \"Forzar limites de bitrate en el servicio de streaming\"." -Basic.Settings.Output.Simple.Warn.AudioBitrate="ADVERTENCIA: El streaming de audio se establecerá a %1, que es el límite superior para el servicio de streaming actual. Si estás seguro que quieres ir por encima de %1, active las opciones avanzadas del codificador y desactive \"Forzar limites de bitrate en el servicio de streaming\"." +Basic.Settings.Output.Simple.Warn.VideoBitrate="Advertencia: La tasa de bits de vídeo del stream se establecerá en %1, que es el límite superior para el servicio de streaming actual." +Basic.Settings.Output.Simple.Warn.AudioBitrate="Advertencia: La tasa de bits de audio del stream se establecerá en %1, que es el límite superior para el servicio de streaming actual." Basic.Settings.Output.Simple.Warn.CannotPause="Advertencia: Las grabaciones no se pueden pausar si la calidad de grabación se establece en \"Igual al stream\"." Basic.Settings.Output.Simple.Warn.Encoder="ADVERTENCIA: Grabar con un codificador de software de una calidad diferente a la de la transmisión requerirá un uso adicional de la CPU si transmite y graba al mismo tiempo." Basic.Settings.Output.Simple.Warn.Lossless="ADVERTENCIA: ¡La calidad sin perdidas genera tamaños de archivo muy grandes! La calidad sin pérdidas puede utilizar más de 7 gigabytes de espacio en disco por minuto en alta resolución y con alta tasa de fotogramas. La calidad sin pérdidas no se recomienda para grabaciones largas, a menos que tenga una gran cantidad de espacio en disco disponible." @@ -674,6 +687,11 @@ 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.Simple.TwitchVodTrack="Pista VOD de Twitch (utiliza la pista 2)" +Basic.Settings.Output.Warn.EnforceResolutionFPS.Title="Resolución o tasa de fotogramas incompatible" +Basic.Settings.Output.Warn.EnforceResolutionFPS.Msg="Este servicio de streaming no admite su resolución y/o tasa de fotogramas actual. Se cambiarán a los valores compatibles más cercanos\n\n%1\n\n¿Desea continuar?" +Basic.Settings.Output.Warn.EnforceResolutionFPS.Resolution="Resolución: %1" +Basic.Settings.Output.Warn.EnforceResolutionFPS.FPS="Tasa de fotogramas: %1" Basic.Settings.Output.VideoBitrate="Bitrate de vídeo" Basic.Settings.Output.AudioBitrate="Bitrate de audio" Basic.Settings.Output.Reconnect="Reconectar automáticamente" @@ -688,15 +706,16 @@ Basic.Settings.Output.NoSpaceFileName="Generar el nombre del archivo sin espacio Basic.Settings.Output.Adv.Rescale="Cambiar la escala de salida" Basic.Settings.Output.Adv.AudioTrack="Pista de audio" Basic.Settings.Output.Adv.Streaming="Emisión" -Basic.Settings.Output.Adv.ApplyServiceSettings="Aplicar ajustes de codificador de servicio streaming" Basic.Settings.Output.Adv.Audio.Track1="Pista 1" Basic.Settings.Output.Adv.Audio.Track2="Pista 2" Basic.Settings.Output.Adv.Audio.Track3="Pista 3" Basic.Settings.Output.Adv.Audio.Track4="Pista 4" Basic.Settings.Output.Adv.Audio.Track5="Pista 5" Basic.Settings.Output.Adv.Audio.Track6="Pista 6" +Basic.Settings.Output.Adv.TwitchVodTrack="Pista VOD de Twitch" Basic.Settings.Output.Adv.Recording="Grabación" +Basic.Settings.Output.Adv.Recording.RecType="Tipo de grabación" Basic.Settings.Output.Adv.Recording.Type="Tipo" Basic.Settings.Output.Adv.Recording.Type.Standard="Estándar" Basic.Settings.Output.Adv.Recording.Type.FFmpegOutput="Salida personalizada (FFmpeg)" @@ -824,13 +843,18 @@ Basic.AdvAudio="Propiedades de Audio avanzadas" Basic.AdvAudio.ActiveOnly="Sólo fuentes activas" Basic.AdvAudio.Name="Nombre" Basic.AdvAudio.Volume="Volumen" +Basic.AdvAudio.VolumeSource="Volumen para '%1'" Basic.AdvAudio.Mono="Mono" +Basic.AdvAudio.MonoSource="Mezcla monoaural para '%1'" Basic.AdvAudio.Balance="Balance" +Basic.AdvAudio.BalanceSource="Balance para '%1'" Basic.AdvAudio.SyncOffset="Intervalo de sincronización" +Basic.AdvAudio.SyncOffsetSource="Compensación de sincronismo para '%1'" Basic.AdvAudio.Monitoring="Monitorización de audio" Basic.AdvAudio.Monitoring.None="Monitorización desactivada" Basic.AdvAudio.Monitoring.MonitorOnly="Solo monitorización (silenciar la salida)" Basic.AdvAudio.Monitoring.Both="Monitorización y salida" +Basic.AdvAudio.MonitoringSource="Monitorización de audio para '%1'" Basic.AdvAudio.AudioTracks="Pistas" Basic.Settings.Hotkeys="Atajos" diff --git a/UI/data/locale/et-EE.ini b/UI/data/locale/et-EE.ini index 6440ca9..92c162c 100644 --- a/UI/data/locale/et-EE.ini +++ b/UI/data/locale/et-EE.ini @@ -85,13 +85,18 @@ Calculating="Arvutamine..." Fullscreen="Täisekraan" Windowed="Akendatud" Percent="Protsent" +RefreshBrowser="Värskenda" AspectRatio="Kuvasuhe %1:%2" LockVolume="Lukusta helitugevus" +ShowOnStartup="Kuva käivitamisel" +OpenFile="Ava fail" +AddValue="Lisa %1" AlreadyRunning.Title="OBS juba töötab" AlreadyRunning.Text="OBS on juba käivitatud! Palun välju olemasolevatest protsessidest enne kui alustad uut. Kui OBS on minimeeritud süsteemi salve, siis kontrolli kas see on seal." AlreadyRunning.LaunchAnyway="Käivita siiski" +ChromeOS.Title="Toetuseta platvorm" DockCloseWarning.Title="Dokitava akna sulgemine" DockCloseWarning.Text="Sa just sulgesid dokitava akna. Kui sa tahad seda näidata uuesti, kasuta Vaade → Dokid menüüd menüüribal." @@ -149,6 +154,7 @@ Basic.AutoConfig.StreamPage.ConnectAccount="Ühenda konto (soovitatud)" Basic.AutoConfig.StreamPage.DisconnectAccount="Katkesta ühendus kontoga" Basic.AutoConfig.StreamPage.DisconnectAccount.Confirm.Title="Katkesta ühendus kontoga?" Basic.AutoConfig.StreamPage.GetStreamKey="Taotle voogedastuse võti" +Basic.AutoConfig.StreamPage.MoreInfo="Lisateave" Basic.AutoConfig.StreamPage.UseStreamKey="Kasuta voogedastuse võtit" Basic.AutoConfig.StreamPage.Service="Teenus" Basic.AutoConfig.StreamPage.Service.ShowAll="Kuva kõik..." @@ -157,6 +163,7 @@ Basic.AutoConfig.StreamPage.Server="Server" Basic.AutoConfig.StreamPage.StreamKey="Voogedastuse võti" Basic.AutoConfig.StreamPage.StreamKey.LinkToSite="(Link)" Basic.AutoConfig.TestPage="Lõpptulemused" +Basic.AutoConfig.TestPage.TestingBandwidth.Connecting="Ühendamine: %1..." Basic.Stats="Statistika" Basic.Stats.CPUUsage="CPU kasutus" @@ -305,6 +312,7 @@ Basic.SourceSelect.CreateNew="Loo uus" Basic.SourceSelect.AddExisting="Lisa olemasolev" Basic.SourceSelect.AddVisible="Tee allikas nähtavaks" + Basic.PropertiesWindow="'%1' omadused" Basic.PropertiesWindow.SelectColor="Vali värv" Basic.PropertiesWindow.SelectFont="Vali font" diff --git a/UI/data/locale/eu-ES.ini b/UI/data/locale/eu-ES.ini index c58b795..66d61b4 100644 --- a/UI/data/locale/eu-ES.ini +++ b/UI/data/locale/eu-ES.ini @@ -37,6 +37,7 @@ SceneWindow="Leihodun proiektorea (Eszena)" SourceWindow="Leihodun proiektorea (iturburua)" MultiviewProjector="Ikuspegi anitza (pantaila osoan)" MultiviewWindowed="Ikuspegi anitza (leihoan)" +ResizeProjectorWindowToContent="Leihoa edukiari egokitu" Clear="Garbitu" Revert="Leheneratu" Show="Erakutsi" @@ -86,13 +87,20 @@ Calculating="Kalkulatzen..." Fullscreen="Pantaila osoa" Windowed="Leihoan" Percent="Ehunekoa" +RefreshBrowser="Eguneratu" AspectRatio="Aspektu-erlazioa %1:%2" LockVolume="Blokeatu bolumena" +LogViewer="Ikusi Erregistroa" +ShowOnStartup="Ireki hasterakoan" +OpenFile="Ireki fitxategia" +AddValue="Gehitu %1" AlreadyRunning.Title="OBS dagoeneko martxan dago" AlreadyRunning.Text="OBS dagoeneko martxan dago! Bestelakorik nahi ez baduzu Itxi irekita dagoen saioa beste saio bat ireki baino lehen. Ezarri baduzu OBS agertzea minimizatua sistemaren erretiluan begiratu eta oraindik exekutatzen ari den bertan." AlreadyRunning.LaunchAnyway="Abiarazi hala ere" +ChromeOS.Title="Euskarririk gabeko plataforma" +ChromeOS.Text="Badirudi OBS ChromeOS edukiontzi baten barruan dabilela. Plataforma honek ez du euskarririk" DockCloseWarning.Title="Leiho moldagarria ixten" DockCloseWarning.Text="Leiho moldagarri bat itxi berri duzu. Berriro bistaratu nahi baduzu, erabili menu barrako Ikusi → Leiho moldagarriak menua." @@ -137,7 +145,9 @@ Basic.AutoConfig.StartPage="Erabilera-informazioa" Basic.AutoConfig.StartPage.SubTitle="Zehaztu zertarako erabili nahi duzun programa" Basic.AutoConfig.StartPage.PrioritizeStreaming="Optimizatu transmisiorako, grabazioa bigarren mailakoa da" Basic.AutoConfig.StartPage.PrioritizeRecording="Optimizatu grabazioa, ez du transmitituko" +Basic.AutoConfig.StartPage.PrioritizeVirtualCam="Kamera birtuala bakarrik erabiliko dut" Basic.AutoConfig.VideoPage="Bideo-ezarpenak" +Basic.AutoConfig.VideoPage.SubTitle="Zehaztu erabili nahi dituzun bideo-ezarpenak" Basic.AutoConfig.VideoPage.BaseResolution.UseCurrent="Erabili unekoa (%1x%2)" Basic.AutoConfig.VideoPage.BaseResolution.Display="Erakutsi %1 (%2x%3)" Basic.AutoConfig.VideoPage.FPS.UseCurrent="Erabili unekoa (%1)" @@ -151,6 +161,7 @@ Basic.AutoConfig.StreamPage.DisconnectAccount="Deskonektatu kontua" Basic.AutoConfig.StreamPage.DisconnectAccount.Confirm.Title="Kontua deskonektatu?" Basic.AutoConfig.StreamPage.DisconnectAccount.Confirm.Text="Aldaketa hau berehalakoan aplika daiteke. Ziur zaude kontua deskonektatu nahi duzula?" Basic.AutoConfig.StreamPage.GetStreamKey="Lortu transmisio giltza" +Basic.AutoConfig.StreamPage.MoreInfo="Informazio Gehiago" Basic.AutoConfig.StreamPage.UseStreamKey="Erabili transmisio giltza" Basic.AutoConfig.StreamPage.Service="Zerbitzua" Basic.AutoConfig.StreamPage.Service.ShowAll="Erakutsi denak..." @@ -179,6 +190,8 @@ Basic.AutoConfig.TestPage.Result.StreamingEncoder="Transmisioaren kodetzailea" Basic.AutoConfig.TestPage.Result.RecordingEncoder="Grabazioaren kodetzailea" Basic.AutoConfig.TestPage.Result.Header="Programaren arabera hauek dira zuretzako ezarpenik egokienak:" Basic.AutoConfig.TestPage.Result.Footer="Ezarpen hauek onartzeko, klika Aplikatu ezarpenak. Morroiaren bidez birkonfiguratzeko eta saiatzeko berriro klika Atzera. Ezarpenak eskuz zehazteko klika Utzi eta ireki Ezarpenak." +Basic.AutoConfig.Info="Autokonfigurazio-laguntzaileak konfiguraziorik onena zehaztuko du, bere ordenagailuaren zehaztapenen eta Interneteko abiaduraren arabera." +Basic.AutoConfig.RunAnytime="Hori edozein unetan exekutatu daiteke, Tresnak menura joatean." Basic.Stats="Estatistikak" Basic.Stats.CPUUsage="PUZ erabilpena" @@ -293,7 +306,10 @@ Output.BadPath.Title="Fitxategi-bide okerra" Output.BadPath.Text="Ezarritako fitxategiaren irteera-bidea baliogabea da. Egiaztatu zure ezarpenak baieztatzeko baliozko fitxategi-bidea ezarri dela." LogReturnDialog="Egunkaria ongi kargatu da" +LogReturnDialog.Description="Istripuaren txostena igo da. Orain, URLa partekatu dezakezu, arazteko." +LogReturnDialog.Description.Crash="Istripuaren txostena igo da. Orain, URLa partekatu dezakezu, arazteko." LogReturnDialog.CopyURL="Kopiatu URL-a" +LogReturnDialog.AnalyzeURL="Aztertu" LogReturnDialog.ErrorUploadingLog="Errorea egunkari-fitxategia kargatzean" Remux.SourceFile="OBS grabazioa" @@ -350,8 +366,6 @@ Deinterlacing.Yadif2x="Yadif 2x" Deinterlacing.TopFieldFirst="Goiko eremua lehenik" Deinterlacing.BottomFieldFirst="Beheko eremua lehenik" -VolControl.SliderUnmuted="Bolumen graduatzailea '%1'-rentzat: %2" -VolControl.SliderMuted="Bolumen graduatzailea '%1'-rentzat: %2 (une honetan mutu)" VolControl.Mute="Mututu '%1'" VolControl.Properties="'%1'-ren ezaugarriak" @@ -367,6 +381,7 @@ Basic.Main.RenameSceneCollection.Title="Berrizendatu eszena-bilduma" AddProfile.Title="Gehitu profila" AddProfile.Text="Sartu profilaren izena" +AddProfile.WizardCheckbox="Ezarpen automatikoen laguntzailea" RenameProfile.Title="Aldatu izena profilari" @@ -381,6 +396,7 @@ Basic.SourceSelect.CreateNew="Sortu berria" Basic.SourceSelect.AddExisting="Gehitu lehendik dagoena" Basic.SourceSelect.AddVisible="Egin iturburua ikusgarri" + Basic.PropertiesWindow="'%1'-ren ezaugarriak" Basic.PropertiesWindow.AutoSelectFormat="%1 (berez-hautatu: %2)" Basic.PropertiesWindow.SelectColor="Hautatu kolorea" @@ -457,6 +473,7 @@ Basic.Main.StartRecording="Hasi grabazioa" Basic.Main.StartReplayBuffer="Abiatu erreprodukzio bufferra" Basic.Main.SaveReplay="Gorde erreprodukzioa" Basic.Main.StartStreaming="Hasi transmisioa" +Basic.Main.StartVirtualCam="Hasi Kamera Birtuala" Basic.Main.StopRecording="Gelditu grabazioa" Basic.Main.PauseRecording="Pausatu grabazioa" Basic.Main.UnpauseRecording="Amaitu grabazioaren pausa" @@ -466,6 +483,9 @@ Basic.Main.StoppingReplayBuffer="Erreprodukzio bufferra gelditzen..." Basic.Main.StopStreaming="Gelditu transmisioa" Basic.Main.StoppingStreaming="Transmisioa gelditzen..." Basic.Main.ForceStopStreaming="Gelditu transmisioa (baztertu atzerapena)" +Basic.Main.ShowContextBar="Erakutsi Iturriko Tresna-Barra" +Basic.Main.HideContextBar="Izkutatu Iturriko Tresna-Barra" +Basic.Main.StopVirtualCam="Amaitu Kamera Birtuala" Basic.Main.Group="%1 taldea" Basic.Main.GroupItems="Batu hautatutako elementuak" Basic.Main.Ungroup="Banatu" @@ -614,13 +634,14 @@ Basic.Settings.Stream.StreamSettingsWarning="Ireki ezarpenak" Basic.Settings.Stream.MissingUrlAndApiKey="Transmisioaren URLa eta gakoa falta dira.\n\nIreki ezarpenak sartzeko URLa eta transmisioaren gakoa 'transmisioa' fitxan." Basic.Settings.Stream.MissingUrl="Trasnsmisioaren URLa falta da.\n\nIreki ezarpenak sartzeko URLa 'Transmisioa' fitxan." Basic.Settings.Stream.MissingStreamKey="Transmisioaren gakoa falta da.\n\nIreki ezarpenak sartzeko transmisioaren gakoa 'Transmisioa' fitxan." +Basic.Settings.Stream.IgnoreRecommended="Streaming zerbitzua konfiguratzeko gomendioak alde batera utzi" +Basic.Settings.Stream.IgnoreRecommended.Warn.Title="Gomendatutako Doikuntzak Baliogabetu" Basic.Settings.Output="Irteera" Basic.Settings.Output.Format="Grabazio-formatua" Basic.Settings.Output.Encoder="Kodetzailea" Basic.Settings.Output.SelectDirectory="Hautatu grabazioaren karpeta" Basic.Settings.Output.SelectFile="Hautatu grabazioaren fitxategia" -Basic.Settings.Output.EnforceBitrate="Behartu transmisio zerbitzuaren bit-tasaren mugak" Basic.Settings.Output.DynamicBitrate="Aldatu bit-emaria dinamikoki pilaketa kudeatzeko" Basic.Settings.Output.DynamicBitrate.Beta="Aldatu bit-emaria dinamikoki pilaketa kudeatzeko (Beta)" Basic.Settings.Output.DynamicBitrate.TT="Pilaketa murrizteko fotogramak askatu beharrean, abiadura dinamikoki aldatzen du.\n\n Kontuan izan horrek ikuslearentzat atzerapena areagotu dezakeela bat-bateko pilaketak nabarmenak badira.\nBit-emaria jaisten denean, minutu batzuk iraun dezake berreskuratzeak.\n\nUne honetan bakarrik RTMPrako onartzen da." @@ -641,8 +662,6 @@ Basic.Settings.Output.Simple.RecordingQuality.Stream="Transmisioaren berdina" Basic.Settings.Output.Simple.RecordingQuality.Small="Kalitate altua. Fitxategi-tamaina ertaina" Basic.Settings.Output.Simple.RecordingQuality.HQ="Bereizigabeko kalitatea. Fitxategi-tamaina handia" Basic.Settings.Output.Simple.RecordingQuality.Lossless="Galerarik gabeko kalitatea. Fitxategi-tamaina izugarri handia" -Basic.Settings.Output.Simple.Warn.VideoBitrate="Kontuz: transmisioaren bideoaren bit-tasa %1 ean ezarriko da; hau izango da oraingo transmisio zerbitzuaren goiko muga. Seguru bazaude %1 aren gainetik nahi duzula, gaitu kodetze aukera aurreratuak eta desautatu \"Behartu transmisio zerbitzuaren bit-tasaren mugak\"." -Basic.Settings.Output.Simple.Warn.AudioBitrate="Kontuz: transmisioaren audioaren bit-tasa %1 ean ezarriko da; hau izango da oraingo transmisio zerbitzuaren goiko muga. Seguru bazaude %1 aren gainetik nahi duzula, gaitu kodetze aukera aurreratuak eta desautatu \"Behartu transmisio zerbitzuaren bit-tasaren mugak\"." Basic.Settings.Output.Simple.Warn.CannotPause="Kontuz: Grabazioa ezin da pausatu grabazioaren kalitatearen konfigurazioa \"jarioaren berdina\" bada." Basic.Settings.Output.Simple.Warn.Encoder="Oharra: Transmisioak duen kalitatea ez bestelako kalitate batez grabatzeak PUZ-ren aparteko erabilera eskatzen du une berean transmititzen eta grabatzen baduzu." Basic.Settings.Output.Simple.Warn.Lossless="Oharra: Galerarik gabeko kalitateak neurri izugarri handiko fitxategiak sortzen ditu! Galerarik gabeko kalitateak minutuko 7 gigabytetik gorako tokia erabili dezake diskoan bereizmen eta fotograma-emari handietan. Galerarik gabeko kalitatea ez dago gomendatua grabazio luzeetarako disko toki eskuragarri oso handi bat ez baduzu." @@ -653,6 +672,7 @@ Basic.Settings.Output.Simple.Encoder.Hardware.QSV="Hardwarea (QSV)" Basic.Settings.Output.Simple.Encoder.Hardware.AMD="Hardwarea (AMD)" Basic.Settings.Output.Simple.Encoder.Hardware.NVENC="Hardwarea (NVENC)" Basic.Settings.Output.Simple.Encoder.SoftwareLowCPU="Softwarea (x264 PUZ erabilpen apaleko aurre-ezarpena, fitxategiaren tamaina handitzen du)" +Basic.Settings.Output.Warn.EnforceResolutionFPS.Title="Ebazpen Bateraezina" Basic.Settings.Output.VideoBitrate="Bideo bit-emaria" Basic.Settings.Output.AudioBitrate="Audio bit-emaria" Basic.Settings.Output.Reconnect="Automatikoki birkonektatu" @@ -667,7 +687,6 @@ Basic.Settings.Output.NoSpaceFileName="Sortu tarterik gabeko fitxategi-izena" Basic.Settings.Output.Adv.Rescale="Eskala-aldaketaren Irteera" Basic.Settings.Output.Adv.AudioTrack="Audio-pista" Basic.Settings.Output.Adv.Streaming="Transmisioa" -Basic.Settings.Output.Adv.ApplyServiceSettings="Behartu transmisio-zerbitzu kodetzaileren ezarpenak" Basic.Settings.Output.Adv.Audio.Track1="1 pista" Basic.Settings.Output.Adv.Audio.Track2="2 pista" Basic.Settings.Output.Adv.Audio.Track3="3 pista" @@ -745,6 +764,7 @@ Basic.Settings.Audio.PeakMeterType.TruePeak="Benetako gailurra (CPUaren erabiler Basic.Settings.Audio.MultiChannelWarning.Enabled="Kontu: soinu inguratzailea aktibatuta dago." Basic.Settings.Audio.MultichannelWarning.Title="Nahi duzu soinu inguratzailea aktibatzea?" Basic.Settings.Audio.MultichannelWarning.Confirm="Seguru zaude soinu inguratzailea aktibatu nahi duzula?" +Basic.Settings.Audio.Devices="Audio-Gailu Globala" Basic.Settings.Audio.DesktopDevice="Mahaigaineko audioa" Basic.Settings.Audio.DesktopDevice2="Mahaigaineko audioa 2" Basic.Settings.Audio.AuxDevice="Mik/Audio osagarria" @@ -908,5 +928,13 @@ Importer.AutomaticCollectionText="OBSek bilatu dezake era automatikoan eszena in Restart="Berrabiarazi" NeedsRestart="OBS Studio berrabiarazi behar da. Nahi duzu orain berrabiaraztea?" +ContextBar.NoSelectedSource="Ez da iturririk hautatu" +ContextBar.MediaControls.PlayMedia="Erreproduzitu Media" +ContextBar.MediaControls.PauseMedia="Media Pausatu" +ContextBar.MediaControls.StopMedia="Gelditu media" +ContextBar.MediaControls.RestartMedia="Berrabiarazi Media" +ContextBar.MediaControls.PlaylistNext="Hurrengoa Erreprodukzio-zerrendan" +ContextBar.MediaControls.PlaylistPrevious="Aurrekoa Erreprodukzio-zerrendan" +ContextBar.MediaControls.MediaProperties="Media propietateak" diff --git a/UI/data/locale/fa-IR.ini b/UI/data/locale/fa-IR.ini index 304ae68..3425330 100644 --- a/UI/data/locale/fa-IR.ini +++ b/UI/data/locale/fa-IR.ini @@ -37,6 +37,7 @@ SceneWindow="پروژکتور پنجره ای (صحنه)" SourceWindow="پروژکتور پنجره ای (منبع)" MultiviewProjector="حالت چند نمایی (تمام صفحه)" MultiviewWindowed="حالت چند نمایی (پنجره ای)" +ResizeProjectorWindowToContent="ست کردن پنجره بر روی محتوا" Clear="پاک کردن" Revert="برگرداندن" Show="نمایش" @@ -86,13 +87,20 @@ Calculating="در حال محاسبه..." Fullscreen="تمام صفحه" Windowed="پنجره" Percent="درصد" +RefreshBrowser="تازه سازی" AspectRatio="نسبت ابعاد %1:%2" LockVolume="قفل تنظیم صدا" +LogViewer="نمایشگر گزارش" +ShowOnStartup="نمایش هنگام راه اندازی" +OpenFile="بازکردن پرونده" +AddValue="افزودن %1" AlreadyRunning.Title="OBS از قبل در حال اجراست" AlreadyRunning.Text="OBS از قبل در حال اجراست! در صورتی که به صورت عمد این کار را کرده اید، لطفاً قبل از اجرای یک نمونه جدید سایر نمونه های باز شده‌ی OBS را ببندید. اگر OBS را در حالت کوچک کردن در system try قرار داده اید، لطفاً چک کنید که آیا در آن جا هنوز در حال اجراست." AlreadyRunning.LaunchAnyway="در هر حال اجرا کن" +ChromeOS.Title="پلتفرم پشتیبانی نشده" +ChromeOS.Text="به نظر می رسد OBS در داخل ظرف سیستم عامل Chrome در حال اجرا است. این سیستم عامل پشتیبانی نمی شود" DockCloseWarning.Title="بسته شدن پنجره قابل حمل" DockCloseWarning.Text="شما فقط یک پنجره قابل حمل را بسته اید. اگر می خواهید دوباره آن را نشان دهید ، از منوی نما زیر منوی بخش ها در نوار فهرست استفاده کنید." @@ -110,6 +118,7 @@ Auth.InvalidScope.Text="الزامات تأیید اعتبار برای %1 تغ Auth.LoadingChannel.Title="بارگیری اطلاعات کانال..." Auth.LoadingChannel.Text="در حال بارگیری اطلاعات کانال %1، لطفاً صبر کنید..." Auth.ChannelFailure.Title="کانال بارگیری نشد" +Auth.ChannelFailure.Text="اطلاعات کانال برای %1\n\n%2: %3 بارگیری نشد" Auth.Chat="چت" Auth.StreamInfo="اطلاعات پخش زنده" TwitchAuth.Stats="وضعیت توییچ" @@ -136,7 +145,9 @@ Basic.AutoConfig.StartPage="اطلاعات نحوه استفاده" Basic.AutoConfig.StartPage.SubTitle="تعیین کنید که از برنامه برای چه کاری می‌خواهید استفاده کنید" Basic.AutoConfig.StartPage.PrioritizeStreaming="بهینه سازی برای پخش زنده، ضبط اولویت دوم است" Basic.AutoConfig.StartPage.PrioritizeRecording="فقط برای ضبط بهینه سازی می کنم ، پخش زنده ندارم" +Basic.AutoConfig.StartPage.PrioritizeVirtualCam="من فقط از دوربین مجازی استفاده خواهم کرد" Basic.AutoConfig.VideoPage="تنظیمات ویدئو" +Basic.AutoConfig.VideoPage.SubTitle="تنظیمات ویدئویی را که می خواهید استفاده کنید مشخص کنید" Basic.AutoConfig.VideoPage.BaseResolution.UseCurrent="استفاده از فعلی (%1x%2)" Basic.AutoConfig.VideoPage.BaseResolution.Display="صفحه نمایش %1 (%2x%3)" Basic.AutoConfig.VideoPage.FPS.UseCurrent="استفاده از فعلی (%1)" @@ -150,6 +161,7 @@ Basic.AutoConfig.StreamPage.DisconnectAccount="خروج از حساب کاربر Basic.AutoConfig.StreamPage.DisconnectAccount.Confirm.Title="آیا می خواهید از حساب کاربری خارج شوید?" Basic.AutoConfig.StreamPage.DisconnectAccount.Confirm.Text="این تغییر بلافاصله اعمال می شود. آیا مطمئن هستید که می خواهید از حساب کاربری خود خارج شوید?" Basic.AutoConfig.StreamPage.GetStreamKey="دریافت کلید پخش زنده" +Basic.AutoConfig.StreamPage.MoreInfo="اطلاعات بیشتر" Basic.AutoConfig.StreamPage.UseStreamKey="کلید پخش زنده" Basic.AutoConfig.StreamPage.Service="سرویس" Basic.AutoConfig.StreamPage.Service.ShowAll="نمایش همه..." @@ -172,39 +184,69 @@ Basic.AutoConfig.TestPage.TestingBandwidth.Server="در حال تست پهنای Basic.AutoConfig.TestPage.TestingStreamEncoder="در حال تست encoder استریم، این عملیات ممکن است کمی طول بکشد..." Basic.AutoConfig.TestPage.TestingRecordingEncoder="در حال تست encoder ضبط، این عملیات ممکن است کمی طول بکشد..." Basic.AutoConfig.TestPage.TestingRes="در حال تست رزولوشن‌ها، این عملیات ممکن است چند دقیقه‌ای طول بکشد..." +Basic.AutoConfig.TestPage.TestingRes.Fail="رمزگذار راه اندازی نشد" +Basic.AutoConfig.TestPage.TestingRes.Resolution="تست کردن %1x%2 %3 ف‌ب‌س..." +Basic.AutoConfig.TestPage.Result.StreamingEncoder="استریم" +Basic.AutoConfig.TestPage.Result.RecordingEncoder="رمزگذار ضبط" +Basic.AutoConfig.TestPage.Result.Header="این برنامه تعیین کرده است که این تنظیمات تخمینی بهترین گزینه برای شما هستند:" +Basic.AutoConfig.TestPage.Result.Footer="برای استفاده از این تنظیمات، روی اعمال تنظیمات کلیک کنید. برای پیکربندی مجدد جادوگر و دوباره امتحان کردن، روی بازگشت کلیک کنید. برای پیکربندی دستی تنظیمات خود، روی لغو کلیک کنید و تنظیمات را باز کنید." +Basic.AutoConfig.Info="جادوگر پیکربندی خودکار بهترین تنظیمات را براساس مشخصات رایانه و سرعت اینترنت شما تعیین می کند." +Basic.AutoConfig.RunAnytime="این کار در هر زمان با رفتن به منوی ابزار قابل اجرا است." Basic.Stats="آمارها" Basic.Stats.CPUUsage="میزان استفاده CPU" Basic.Stats.HDDSpaceAvailable="فضای در دسترس دیسک" Basic.Stats.MemoryUsage="میزان استفاده حافظه" Basic.Stats.AverageTimeToRender="متوسط زمان ارائه فریم" +Basic.Stats.SkippedFrames="فریمها به دلیل تأخیر رمزگذاری رد شدند" +Basic.Stats.MissedFrames="فریم ها به دلیل تأخیر در رندر رد شدند" Basic.Stats.Output.Stream="پخش جریانی" Basic.Stats.Output.Recording="درحال ضبط" Basic.Stats.Status="وضعیت" Basic.Stats.Status.Recording="درحال ضبط" -Basic.Stats.Status.Live="زنده" +Basic.Stats.Status.Live="پخش زنده" Basic.Stats.Status.Reconnecting="اتصال مجدد" Basic.Stats.Status.Inactive="غیر فعال" Basic.Stats.Status.Active="فعال" Basic.Stats.DroppedFrames="فریم های از دست رفته (شبکه)" Basic.Stats.MegabytesSent="مجموع خروجی داده ها" Basic.Stats.Bitrate="نرخ بیت" +Basic.Stats.DiskFullIn="دیسک کامل (تقریباً)" Basic.Stats.ResetStats="تنظیم مجدد آمار" ResetUIWarning.Title="آیا مطمئنید که می‌خواهید رابط کاربری را مجدداً تنظیم کنید؟" +ResetUIWarning.Text="با بازنشانی رابط کاربری، اسکله های اضافی پنهان می شوند. اگر می خواهید این اسکله ها قابل مشاهده باشند، باید از فهرست نمایش قبال نمایش شوند.\n\nآیا مطمئن هستید که می خواهید رابط را مجدداً تنظیم کنید?" Updater.Title="بروزرسانی جدید موجود است" Updater.Text="نسخه جدیدی در دسترس است:" Updater.UpdateNow="اکنون بروزرسانی شود" Updater.RemindMeLater="بعدا یادآوری کن" +Updater.Skip="رد شدن از نسخه" +Updater.Running.Title="درحال حاضر برنامه فعال است" +Updater.Running.Text="درحال حاضر خروجی ها فعال هستند ، لطفا پیش از بروزرسانی هر خروجی فعال را خاموش کنید" Updater.NoUpdatesAvailable.Title="بروزرسانی موجود نیست" Updater.NoUpdatesAvailable.Text="در حال حاظر بروزرسانی در دسترس نیست" Updater.FailedToLaunch="اجرای بروزرسانی کننده ناموفق بود" +Updater.GameCaptureActive.Title="گیم کپچر فعال است" +Updater.GameCaptureActive.Text="گیرنده کتابخانه گیم کپچر درحال استفاده شدن است. لطفا هر گیم / برنامه ای را قبل از گرفتن ببندید. (یا ویندوز را راه اندازی مجدد کنید) و دوباره تلاش کنید." +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="صحنه ها" @@ -222,18 +264,28 @@ ConfirmStop.Title="قطع استریم؟" ConfirmStop.Text="آیا مطمئنید که می‌خواهید استریم را قطع کنید؟" ConfirmStopRecord.Title="توقف ضبط؟" +ConfirmStopRecord.Text="مطمئن هستید که می خواهید ضبط کردن را متوقف کنید؟" +ConfirmBWTest.Title="شروع تست پهنای باند؟" +ConfirmBWTest.Text="شما OBS را در حالت آزمایش پهنای باند پیکربندی کرده اید. این حالت امکان آزمایش شبکه بدون فعال شدن کانال شما را فراهم می کند. پس از پایان آزمایش ، برای اینکه بینندگان بتوانند جریان شما را ببینند ، باید آن را غیرفعال کنید.\n\nآیا می خواهید ادامه دهید?" ConfirmExit.Title="خروج از OBS؟" ConfirmExit.Text="OBS در حال حاظر فعال است. تمامی استریم/ضبط ها قطع خاموش خواهند شد. آیا مطمئنید که می‌خواهید خارج شوید؟" ConfirmRemove.Title="تایید حذف" +ConfirmRemove.Text="آیا مطمئن هستید که می‌خواهید '$1' را حذف کنید؟" +ConfirmRemove.TextMultiple="آیا مطمئن هستید که می‌خواهید %1 آیتم را حذف کنید؟" Output.StartStreamFailed="شروع استریم ناموفق بود" Output.StartRecordingFailed="شروع ضبط ناموفق بود" +Output.StartReplayFailed="بافر پخش مجدد شروع نشد" +Output.StartFailedGeneric="شروع خروجی ناموفق بود. لطفاً جزئیات گزارش را وارد کنید.\n\nتوجه: اگر از رمزگذارهای NVENC یا AMD استفاده می کنید، مطمئن شوید که درایورهای ویدئویی شما به روز هستند." +Output.ReplayBuffer.PauseWarning.Title="ذخیره مجدد هنگام مکث امکان پذیر نیست" +Output.ReplayBuffer.PauseWarning.Text="هشدار: هنگام مکث ضبط، امکان بارگیری مجدد وجود ندارد." Output.ConnectFail.Title="اتصال ناموفق بود" +Output.ConnectFail.BadPath="آدرس اینترنتی یا مسیر اتصال نامعتبر است. لطفاً تنظیمات خود را بررسی کنید تا معتبر بودن آنها را تأیید کنید." Output.ConnectFail.ConnectFailed="اتصال به سرور ممکن نشد" Output.ConnectFail.InvalidStream="نمی توانید به کانال مشخص شده یا کلید پخش زنده دسترسی داشته باشید ، لطفاً کلید جریان خود را دو بار بررسی کنید. اگر صحیح باشد ، ممکن است هنگام اتصال به سرور مشکلی ایجاد شود." Output.ConnectFail.Error="هنگام تلاش برای اتصال به سرور ، یک خطای غیرمنتظره رخ داد. اطلاعات بیشتر در پرونده لاگ." @@ -250,35 +302,103 @@ Output.RecordError.Title="خطای ضبط" Output.RecordError.Msg="هنگام ضبط خطای نامشخص رخ داده است." Output.RecordError.EncodeErrorMsg="هنگام ضبط خطای رمزگذار رخ داده است." +Output.BadPath.Title="مسیر فایل غیر قابل قبول است" +Output.BadPath.Text="مسیر خروجی فایل پیکربندی شده نامعتبر است. لطفاً تنظیمات خود را بررسی کنید تا تأیید کنید مسیر پرونده معتبری تنظیم شده است." +LogReturnDialog="گزارش با موفقیت آپلود شد" +LogReturnDialog.Description="فایل گزارش شما آپلود شد. اکنون می توانید آدرس اینترنتی را برای اشکال زدایی یا اهداف پشتیبانی به اشتراک بگذارید." +LogReturnDialog.Description.Crash="گزارش خرابی شما آپلود شد. اکنون می توانید آدرس اینترنتی را برای اهداف رفع اشکال به اشتراک بگذارید." +LogReturnDialog.CopyURL="رونوشت نشانی" +LogReturnDialog.AnalyzeURL="تجزیه و تحلیل" +LogReturnDialog.ErrorUploadingLog="خطا در آپلود فایل گزارش" +Remux.SourceFile="ضبط کننده او بی اس" +Remux.TargetFile="فایل مورد نظر" +Remux.Remux="بازسازی" +Remux.Stop="توقف بازسازی" +Remux.ClearFinished="پاک کردن موارد تمام شده" +Remux.ClearAll="پاک کردن آیتم ها" +Remux.OBSRecording="ضبط کننده او بی اس" +Remux.FinishedTitle="بازسازی به پایان رسید" +Remux.Finished="ضبط کردن بازسازی شد" +Remux.FinishedError="ضبط کردن بازسازی شد، اما ممکن است پرونده ناقص باشد" +Remux.SelectRecording="انتخاب ضبط OBS..." +Remux.SelectTarget="انتخاب فایل مورد نظر..." Remux.FileExistsTitle="فایل های مورد نظر وجود دارند" Remux.FileExists="فایل های زیر از قبل وجود دارند. آیا می‌خوهید آن‌ها را جایگزین کنید؟" +Remux.ExitUnfinishedTitle="بازسازی در حال انجام" +Remux.ExitUnfinished="بازسازی به پایان نرسیده است ، توقف اکنون ممکن است فایل هدف را غیر قابل استفاده کند. \nآیا مطمئن هستید که می خواهید بازسازی را متوقف کنید?" +Remux.HelpText="پرونده ها را در این پنجره رها کنید تا دوباره اصلاح شود، یا یک سلول خالی \"ضبط OBS\" را انتخاب کنید تا یک فایل را مرور کنید." UpdateAvailable="بروزرسانی جدید در دسترس است" +UpdateAvailable.Text="نسخه %1.%2.%3 اکنون در دسترس است. برای بارگیری اینجا کلیک کنید " Basic.DesktopDevice1="صدای دسکتاپ" Basic.DesktopDevice2="صدای دسکتاپ 2" +Basic.AuxDevice1="میکروفون / Aux" +Basic.AuxDevice2="میکروفون / Aux2" +Basic.AuxDevice3="میکروفون / Aux3" +Basic.AuxDevice4="میکروفون / Aux4" +Basic.Scene="صحنه‌ها" +Basic.DisplayCapture="ضبط صفحه نمایش" Basic.Main.PreviewConextMenu.Enable="فعال سازی پیش‌نمایش" Basic.Main.Preview.Disable="غیرفعال سازی پیش‌نمایش" +ScaleFiltering="فیلتر مقیاس" +ScaleFiltering.Point="نقطه" +ScaleFiltering.Bilinear="دو خطی" +ScaleFiltering.Bicubic="دو مکعبی" +ScaleFiltering.Lanczos="لانچوس" +ScaleFiltering.Area="ناحیه" +Deinterlacing="ضد انعطاف پذیری" +Deinterlacing.Discard="دور انداختن" +Deinterlacing.Retro="گذشته" +Deinterlacing.Blend="مخلوط کردن" +Deinterlacing.Blend2x="مخلوط 2x" +Deinterlacing.Linear="خطی" +Deinterlacing.Linear2x="خطی 2x" +Deinterlacing.Yadif="یدیف" +Deinterlacing.Yadif2x="یدیف 2x" +Deinterlacing.TopFieldFirst="ابتدا فیلد برتر" +Deinterlacing.BottomFieldFirst="ابتدا فیلد پایین" +VolControl.SliderUnmuted="لغزنده میزان صدا برای \"%1\":" +VolControl.SliderMuted="لغزنده میزان صدا برای \"%1\": (فعلا بی صدا)" +VolControl.Mute="بی صدا \"%1\"" +VolControl.Properties="ویژگیهای \"%1\"" +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="لطفاً نام نمایه را وارد کنید" +AddProfile.WizardCheckbox="نمایش جادوگر پیکربندی خودکار" RenameProfile.Title="تغییر نام پروفایل" +Basic.Main.MixerRename.Title="تغییر نام منبع صوتی" +Basic.Main.MixerRename.Text="لطفاً نام منبع صوتی را وارد کنید" +Basic.Main.PreviewDisabled="پیش نمایش در حال حاضر غیرفعال است" +Basic.SourceSelect="ایجاد / انتخاب منبع" +Basic.SourceSelect.CreateNew="ایجاد جدید" +Basic.SourceSelect.AddExisting="اضافه کردن موجود" + +Basic.Main.Sources.Visibility="قابلیت نمایش" +Basic.Main.Sources.Lock="قفل" Basic.PropertiesWindow.SelectColor="انتخاب رنگ" Basic.PropertiesWindow.SelectFont="انتخاب فونت" @@ -294,8 +414,191 @@ Basic.PropertiesWindow.AddURL="اضافه کردن مسیر/آدرس اینتر Basic.Filters="فیلتر ها" Basic.Filters.AsyncFilters="فلیتر های صوتی/ویدیویی" Basic.Filters.AudioFilters="فیلتر های صوتی" +Basic.Filters.AddFilter.Title="نام فیلتر" +Basic.TransformWindow.Position="موقعیت" +Basic.TransformWindow.Rotation="چرخش" Basic.TransformWindow.Size="اندازه" +Basic.TransformWindow.Crop="بریدن" + +Basic.TransformWindow.Alignment.TopLeft="بالا سمت چپ" +Basic.TransformWindow.Alignment.TopCenter="بالا وسط" +Basic.TransformWindow.Alignment.TopRight="بالا سمت راست" +Basic.TransformWindow.Alignment.Center="مرکز" + + + +Basic.Main.Scenes="صحنه ها" +Basic.Main.Sources="منابع" +Basic.Main.Controls="کنترل ها" +Basic.Main.Connecting="در حال اتصال..." +Basic.Main.StartRecording="شروع ضبط" +Basic.Main.SaveReplay="ذخیره پخش مجدد" +Basic.Main.StartStreaming="شروع استریم" +Basic.Main.StartVirtualCam="شروع دوربین مجازی" +Basic.Main.StopRecording="پایان ضبط" +Basic.Main.PauseRecording="توقف ضبط" +Basic.Main.UnpauseRecording="ادامه ضبط" +Basic.Main.StoppingRecording="درحال پایان ضبط..." +Basic.Main.StopReplayBuffer="توقف بافر پخش مجدد" +Basic.Main.StopStreaming="توقف پخش جریانی" +Basic.Main.StoppingStreaming="توقف پخش جریان..." +Basic.Main.ForceStopStreaming="توقف پخش جریانی (تأخیر در صرف نظر کردن)" +Basic.Main.ShowContextBar="نمایش نوار ابزار منبع" +Basic.Main.HideContextBar="پنهان کردن نوار ابزار منبع" +Basic.Main.StopVirtualCam="توقف دوربین مجازی" +Basic.Main.Group="گروه %1" +Basic.Main.Ungroup="لغو گروه بندی" +Basic.Main.GridMode="حالت شبکه" +Basic.Main.ListMode="حالت لیست" + +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.Order.MoveUp="رفتن به &بالا" +Basic.MainMenu.Edit.Order.MoveDown="حرکت به &پایین" + +Basic.MainMenu.View="&نما" +Basic.MainMenu.View.Toolbars="&نوارابزارها" +Basic.MainMenu.View.Docks="اسکله ها" +Basic.MainMenu.View.Docks.ResetUI="بازیابی رابط" +Basic.MainMenu.View.Docks.LockUI="قفل رابط" + +Basic.MainMenu.Profile.Import="وارد کردن نمایه" +Basic.MainMenu.Profile.Export="صادر کردن نمایه" + +Basic.MainMenu.Tools="&ابزارها" + +Basic.MainMenu.Help="&راهنما" +Basic.MainMenu.Help.CheckForUpdates="بررسی برای بروزرسانی" +Basic.MainMenu.Help.About="&درباره" + +Basic.Settings.ConfirmTitle="تایید تغییرات" + +Basic.Settings.General="عمومی" +Basic.Settings.General.Theme="پوسته" +Basic.Settings.General.Language="زبان" +Basic.Settings.General.Projectors="پروژکتورها" +Basic.Settings.General.SysTray="سینی سیستم" +Basic.Settings.General.Preview="پیش‌نمایش" +Basic.Settings.General.Multiview="چند دید" + +Basic.Settings.Stream="پخش جریانی" +Basic.Settings.Stream.StreamType="نوع پخش جریانی" +Basic.Settings.Stream.Custom.UseAuthentication="استفاده از تایید اعتبار" +Basic.Settings.Stream.Custom.Username="نام کاربری" +Basic.Settings.Stream.Custom.Password="رمزعبور" +Basic.Settings.Stream.TTVAddon.None="هیچ‌کدام" +Basic.Settings.Stream.StreamSettingsWarning="باز کردن تنظیمات" +Basic.Settings.Stream.Recommended.MaxVideoBitrate="حداکثر نرخِ بیت ویدیو: %1 ک‌ب‌س" +Basic.Settings.Stream.Recommended.MaxAudioBitrate="حداکثر نرخِ بیت صدا: %1 ک‌ب‌س" + +Basic.Settings.Output="خروجی" +Basic.Settings.Output.Format="فرمت ضبط" +Basic.Settings.Output.Encoder="مبدل فرمت" +Basic.Settings.Output.SelectDirectory="انتخاب پوشه ضبط" +Basic.Settings.Output.Mode="نوع خروجی" +Basic.Settings.Output.Mode.Simple="معمولی" +Basic.Settings.Output.Mode.Adv="پیشرفته" +Basic.Settings.Output.Simple.SavePath="مسیر پوشه ضبط" +Basic.Settings.Output.Simple.RecordingQuality="کیفیت ضبط" +Basic.Settings.Output.Warn.EnforceResolutionFPS.Resolution="رزولوشن: %1" +Basic.Settings.Output.VideoBitrate="ترخ ویدئو" +Basic.Settings.Output.AudioBitrate="نرخ صدا" +Basic.Settings.Output.Reconnect="اتصال دوباره خودکار" + +Basic.Settings.Output.Adv.AudioTrack="تراک صدا" +Basic.Settings.Output.Adv.Streaming="پخش جریانی" + +Basic.Settings.Output.Adv.Recording="درحال ضبط" +Basic.Settings.Output.Adv.Recording.Type="نوع" +Basic.Settings.Output.Adv.Recording.Type.Standard="استاندارد" +Basic.Settings.Output.Adv.FFmpeg.SaveFilter.All="همه فایل ها" +Basic.Settings.Output.Adv.FFmpeg.FormatAudio="صدا" +Basic.Settings.Output.Adv.FFmpeg.FormatVideo="ویدئو" + + + + +Basic.Settings.Video="ویدئو" +Basic.Settings.Video.FPS="فریم" +Basic.Settings.Video.Renderer="خروجی" +Basic.Settings.Video.DisableAero="غیر فعال کردن Aero" + + +Basic.Settings.Audio="صدا" +Basic.Settings.Audio.SampleRate="نرخ نمونه" +Basic.Settings.Audio.Channels="کانال‌ها" +Basic.Settings.Audio.MeterDecayRate.Fast="سریع" +Basic.Settings.Audio.DesktopDevice2="صدای دسکتاپ 2" +Basic.Settings.Audio.Disabled="غیر فعال" + +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.BelowNormal="کمتر از عادی" +Basic.Settings.Advanced.General.ProcessPriority.Idle="بیکار" +Basic.Settings.Advanced.Video.ColorSpace="فضای رنگی" +Basic.Settings.Advanced.Video.ColorRange="محدوده رنگ" +Basic.Settings.Advanced.Video.ColorRange.Partial="جزئی" +Basic.Settings.Advanced.Video.ColorRange.Full="کامل" +Basic.Settings.Advanced.Audio.MonitoringDevice.Default="پیش فرض" +Basic.Settings.Advanced.StreamDelay.Duration="مدت زمان" +Basic.Settings.Advanced.Network="شبکه" + +Basic.AdvAudio.Name="نام" +Basic.AdvAudio.Volume="درجه صدا" +Basic.AdvAudio.VolumeSource="میزان صدا برای \"%1\"" +Basic.AdvAudio.Mono="مونو" +Basic.AdvAudio.Balance="بالانس" +Basic.AdvAudio.AudioTracks="قطعه‌ها" + +Basic.Settings.Hotkeys="کلیدهای میانبر" +Basic.Settings.Hotkeys.Filter="فیلتر" + + +Basic.SystemTray.Show="نمایش" +Basic.SystemTray.Hide="پنهان" + + +Hotkeys.Insert="درج کردن" +Hotkeys.Delete="حذف" +Hotkeys.Home="خانه" +Hotkeys.End="پایان" +Hotkeys.PageUp="بالای صفحه" +Hotkeys.PageDown="پایین صفحه" +Hotkeys.NumLock="قفل اعداد" +Hotkeys.Backspace="برگشت عقب" +Hotkeys.Tab="زبانه" +Hotkeys.Print="چاپ" +Hotkeys.Pause="مکث" +Hotkeys.Left="چپ" +Hotkeys.Right="راست" +Hotkeys.Up="بالا" +Hotkeys.Down="پایین" +Hotkeys.Windows="ویندوز" +Hotkeys.Menu="منو" +Hotkeys.Space="فاصله" +Hotkeys.Escape="Esc" + +Mute="بيصدا" +Unmute="صدادار" @@ -303,36 +606,8 @@ Basic.TransformWindow.Size="اندازه" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +About="درباره" +About.License="مجوز" ResizeOutputSizeOfSource.Continue="آیا مایلید ادامه دهید؟" @@ -340,6 +615,8 @@ ResizeOutputSizeOfSource.Continue="آیا مایلید ادامه دهید؟" +Restart="اجرا مجدد" +ContextBar.MediaControls.PlayMedia="اجرا رسانه" diff --git a/UI/data/locale/fi-FI.ini b/UI/data/locale/fi-FI.ini index 642f542..7393fbf 100644 --- a/UI/data/locale/fi-FI.ini +++ b/UI/data/locale/fi-FI.ini @@ -93,6 +93,7 @@ LockVolume="Lukitse äänitaso" LogViewer="Näytä loki" ShowOnStartup="Näytä käynnistyksessä" OpenFile="Avaa tiedosto" +AddValue="Lisää %1" AlreadyRunning.Title="OBS on jo käynnissä" AlreadyRunning.Text="OBS on jo käynnissä! Ellet tarkoittanut tehdä näin, ole hyvä ja sulje aikaisemmat OBS-prosessit ennen uuden käynnistämistä. Jos olet asettanut OBS:n pienentymään ilmaisinalueelle, varmista ettei se ole siellä yhä päällä." @@ -160,6 +161,7 @@ Basic.AutoConfig.StreamPage.DisconnectAccount="Katkaise yhteys tiliin" Basic.AutoConfig.StreamPage.DisconnectAccount.Confirm.Title="Katkaise yhteys tiliin?" Basic.AutoConfig.StreamPage.DisconnectAccount.Confirm.Text="Tämä muutos tulee voimaan välittömästi. Oletko varma että haluat katkaista yhteyden tiliin?" Basic.AutoConfig.StreamPage.GetStreamKey="Hae striimiavain" +Basic.AutoConfig.StreamPage.MoreInfo="Lisää tietoa" Basic.AutoConfig.StreamPage.UseStreamKey="Käytä striimiavainta" Basic.AutoConfig.StreamPage.Service="Palvelu" Basic.AutoConfig.StreamPage.Service.ShowAll="Näytä kaikki..." @@ -364,8 +366,8 @@ Deinterlacing.Yadif2x="Yadif 2x" Deinterlacing.TopFieldFirst="Ylin kenttä ensin" Deinterlacing.BottomFieldFirst="Alin kenttä ensin" -VolControl.SliderUnmuted="Äänenvoimakkuus '%1': %2" -VolControl.SliderMuted="Äänenvoimakkuus '%1': %2 (mykistetty)" +VolControl.SliderUnmuted="Äänenvoimakkuus '%1':" +VolControl.SliderMuted="Äänenvoimakkuus '%1': (mykistetty)" VolControl.Mute="Mykistä %1" VolControl.Properties="Ominaisuudet %1:lle" @@ -381,6 +383,7 @@ Basic.Main.RenameSceneCollection.Title="Uudelleennimeä Skene-kokoelma" AddProfile.Title="Lisää profiili" AddProfile.Text="Syötä profiilin nimi" +AddProfile.WizardCheckbox="Näytä automaattinen määritystoiminto" RenameProfile.Title="Uudelleennimeä profiili" @@ -395,6 +398,11 @@ Basic.SourceSelect.CreateNew="Luo uusi" Basic.SourceSelect.AddExisting="Lisää olemassaoleva" Basic.SourceSelect.AddVisible="Tee lähteestä näkyvä" +Basic.Main.Sources.Visibility="Näkyvyys" +Basic.Main.Sources.VisibilityDescription="Hallitsee '%1' näkyvyyttä piirtoalueella" +Basic.Main.Sources.Lock="Lukitus" +Basic.Main.Sources.LockDescription="Lukitsee '%1' sijainnin ja koon piirtoalueella" + Basic.PropertiesWindow="Ominaisuudet: %1" Basic.PropertiesWindow.AutoSelectFormat="%1 (automaat.: %2)" Basic.PropertiesWindow.SelectColor="Valitse väri" @@ -634,13 +642,19 @@ Basic.Settings.Stream.StreamSettingsWarning="Avaa Asetukset" Basic.Settings.Stream.MissingUrlAndApiKey="URL-osoite ja Striimiavain puuttuu.\n\nAvaa Asetukset syöttääksesi URL-osoitteen ja Striimiavaimen 'Lähetys' -osiossa." Basic.Settings.Stream.MissingUrl="URL-osoite puuttuu.\n\nAvaa Asetukset syöttääksesi URL-osoitteen 'Lähetys' -osiossa." Basic.Settings.Stream.MissingStreamKey="Lähetysavain puuttuu.\n\nAvaa Asetukset syöttääksesi URL-osoitteen 'Lähetys' -osiossa." +Basic.Settings.Stream.IgnoreRecommended="Älä huomioi palvelun asetusten suosituksia" +Basic.Settings.Stream.IgnoreRecommended.Warn.Title="Ohita suositellut asetukset" +Basic.Settings.Stream.IgnoreRecommended.Warn.Text="Varoitus: Rajoitusten ohittaminen saattaa huonontaa lähetyksen laatua tai estää sinua lähettämästä.\n\nJatka?" +Basic.Settings.Stream.Recommended.MaxVideoBitrate="Kuvan bitrate-maksimi: %1 kbps" +Basic.Settings.Stream.Recommended.MaxAudioBitrate="Äänen bitrate-maksimi: %1 kbps" +Basic.Settings.Stream.Recommended.MaxResolution="Maksimiresoluutio: %1" +Basic.Settings.Stream.Recommended.MaxFPS="Maksimi-FPS: %1" Basic.Settings.Output="Ulostulo" Basic.Settings.Output.Format="Tallennuksen muoto" Basic.Settings.Output.Encoder="Enkooderi" Basic.Settings.Output.SelectDirectory="Valitse tallennuskansio" Basic.Settings.Output.SelectFile="Valitse tallennustiedosto" -Basic.Settings.Output.EnforceBitrate="Rajoita bitrate lähetyspalvelun suosituksiin" Basic.Settings.Output.DynamicBitrate="Muuta bitratea verkon ruuhkautumisen mukaan" Basic.Settings.Output.DynamicBitrate.Beta="Muuta bitratea verkon ruuhkautumisen mukaan (Beta)" Basic.Settings.Output.DynamicBitrate.TT="Framejen pudottamisen sijaan vähentää bitratea automaattisesti verkon ruuhkaantumisen aikana.\n\nHuomaa että tämä saattaa lisätä viivettä katsojille, mikäli verkko ruuhkautuu merkittävästi.\nKun bitrate tippuu, sen nousemisessa saattaa kestää muutamia minuutteja.\n\nTällä hetkellä tuettu vain RTMP:ssä." @@ -661,8 +675,8 @@ Basic.Settings.Output.Simple.RecordingQuality.Stream="Sama kuin lähetyksessä" Basic.Settings.Output.Simple.RecordingQuality.Small="Korkea laatu, keskikokoinen tiedostokoko" Basic.Settings.Output.Simple.RecordingQuality.HQ="Erottamaton laatu, suuri tiedostokoko" Basic.Settings.Output.Simple.RecordingQuality.Lossless="Häviötön laatu, valtava tiedostokoko" -Basic.Settings.Output.Simple.Warn.VideoBitrate="Varoitus: Kuvan bitrate asetetaan arvoon %1, joka on yläraja valitsemassasi palvelussa. Jos haluat varmasti mennä %1:n yli, poista valinta lisäasetuksista kohdasta \"Rajoita bitrate lähetyspalvelun suosituksiin\"." -Basic.Settings.Output.Simple.Warn.AudioBitrate="Varoitus: Äänen bitrate asetetaan arvoon %1, joka on yläraja valitsemassasi palvelussa. Jos haluat varmasti mennä %1:n yli, poista valinta lisäasetuksista kohdasta \"Rajoita bitrate lähetyspalvelun suosituksiin\"." +Basic.Settings.Output.Simple.Warn.VideoBitrate="Varoitus: Kuvan bitrate asetetaan %1, joka on valitun palvelun yläraja." +Basic.Settings.Output.Simple.Warn.AudioBitrate="Varoitus: Äänen bitrate asetetaan %1, joka on valitun palvelun yläraja." Basic.Settings.Output.Simple.Warn.CannotPause="Varoitus: Tallennusta ei voi pysäyttää jos laatu on asetettu \"Sama kuin lähetyksessä\"." Basic.Settings.Output.Simple.Warn.Encoder="Varoitus: Tallentaminen lähetyksestä eroavalla laadulla vaatii prosessorilta lisätyötä jos lähetät ja tallennat samanaikaisesti." Basic.Settings.Output.Simple.Warn.Lossless="Varoitus: Häviötön laatu luo järjettömän kokoisia tiedostoja! Häviötön laatu saattaa käyttää jopa 7 gigatavua levytilastasi minuutissa, mikäli käytät suuria resoluutioita ja korkeita FPS-arvoja. Häviötöntä pakkausta ei suositella pitkiin tallennuksiin ellei sinulla ole todella paljon tallennustilaa käytettävissäsi." @@ -673,6 +687,11 @@ Basic.Settings.Output.Simple.Encoder.Hardware.QSV="Laitteistopohjainen (QSV)" Basic.Settings.Output.Simple.Encoder.Hardware.AMD="Laitteisto (AMD)" Basic.Settings.Output.Simple.Encoder.Hardware.NVENC="Laitteistopohjainen (NVENC)" Basic.Settings.Output.Simple.Encoder.SoftwareLowCPU="Ohjelmistopohjainen (x264 matala CPU-käyttö, lisää tiedostokokoa)" +Basic.Settings.Output.Simple.TwitchVodTrack="Twitch VOD ääniraita (Käyttää raitaa 2)" +Basic.Settings.Output.Warn.EnforceResolutionFPS.Title="Epäyhteensopiva resoluutio/FPS" +Basic.Settings.Output.Warn.EnforceResolutionFPS.Msg="Tämä palvelu ei tue nykyistä ulostulon resoluutiota ja/tai FPS:ää. Nämä asetukset muutetaan lähimpään yhteensopivaan arvoon:\n\n%1\n\nHaluatko jatkaa?" +Basic.Settings.Output.Warn.EnforceResolutionFPS.Resolution="Resoluutio: %1" +Basic.Settings.Output.Warn.EnforceResolutionFPS.FPS="FPS: %1" Basic.Settings.Output.VideoBitrate="Kuvan bitrate" Basic.Settings.Output.AudioBitrate="Äänen bitrate" Basic.Settings.Output.Reconnect="Automaattinen uudelleenyhdistys" @@ -687,15 +706,16 @@ Basic.Settings.Output.NoSpaceFileName="Luo tiedostonimi ilman välilyöntejä" Basic.Settings.Output.Adv.Rescale="Uudelleenskaalaa ulostulo" Basic.Settings.Output.Adv.AudioTrack="Ääniraita" Basic.Settings.Output.Adv.Streaming="Lähetys" -Basic.Settings.Output.Adv.ApplyServiceSettings="Pakota asetukset palvelun suosituksiin" Basic.Settings.Output.Adv.Audio.Track1="Raita 1" Basic.Settings.Output.Adv.Audio.Track2="Raita 2" Basic.Settings.Output.Adv.Audio.Track3="Raita 3" Basic.Settings.Output.Adv.Audio.Track4="Raita 4" Basic.Settings.Output.Adv.Audio.Track5="Raita 5" Basic.Settings.Output.Adv.Audio.Track6="Raita 6" +Basic.Settings.Output.Adv.TwitchVodTrack="Twitch VOD ääniraita" Basic.Settings.Output.Adv.Recording="Tallennus" +Basic.Settings.Output.Adv.Recording.RecType="Tallennuksen tyyppi" Basic.Settings.Output.Adv.Recording.Type="Tyyppi" Basic.Settings.Output.Adv.Recording.Type.Standard="Tavallinen" Basic.Settings.Output.Adv.Recording.Type.FFmpegOutput="Mukautettu lähtö (FFmpeg)" @@ -823,13 +843,18 @@ Basic.AdvAudio="Äänen lisäominaisuudet" Basic.AdvAudio.ActiveOnly="Vain aktiiviset lähteet" Basic.AdvAudio.Name="Nimi" Basic.AdvAudio.Volume="Äänenvoimakkuus" +Basic.AdvAudio.VolumeSource="Äänenvoimakkuus '%1'" Basic.AdvAudio.Mono="Mono" +Basic.AdvAudio.MonoSource="Muuttaa '%1' yksikanavaiseksi" Basic.AdvAudio.Balance="Balanssi" +Basic.AdvAudio.BalanceSource="Äänen tasapaino '%1'" Basic.AdvAudio.SyncOffset="Synkronoinnin viivästys" +Basic.AdvAudio.SyncOffsetSource="Synkronoinnin viivästys '%1'" Basic.AdvAudio.Monitoring="Äänen monitorointi" Basic.AdvAudio.Monitoring.None="Monitorointi pois" Basic.AdvAudio.Monitoring.MonitorOnly="Vain monitorointi (hiljennä ulostulo)" Basic.AdvAudio.Monitoring.Both="Monitorointi ja ulostulo" +Basic.AdvAudio.MonitoringSource="Äänen monitorointi '%1'" Basic.AdvAudio.AudioTracks="Raidat" Basic.Settings.Hotkeys="Pikanäppäimet" diff --git a/UI/data/locale/fil-PH.ini b/UI/data/locale/fil-PH.ini index c305e5e..ff97aab 100644 --- a/UI/data/locale/fil-PH.ini +++ b/UI/data/locale/fil-PH.ini @@ -93,6 +93,7 @@ LockVolume="I-lock ang volume" LogViewer="Viewer para sa Log" ShowOnStartup="Ipakita sa pasimula" OpenFile="Buksan ang file" +AddValue="Magdagdag ng %1" AlreadyRunning.Title="Tumatakbo na ang OBS" AlreadyRunning.Text="Tumatakbo na ang OBS! Maliban na lamang kung gusto mong gawin ito, pakiusap patayin ang anomang umiiral na instansiya ng OBS bago subukang magpatakbo ng panibagong instansiya. Kung itinakda sa OBS na lumiit tungo sa system tray, pakitingnan kung ito ay tumatakbo pa rin doon." @@ -159,6 +160,7 @@ Basic.AutoConfig.StreamPage.DisconnectAccount="I-disconnect ang Account" Basic.AutoConfig.StreamPage.DisconnectAccount.Confirm.Title="I-disconnect ang Account?" Basic.AutoConfig.StreamPage.DisconnectAccount.Confirm.Text="Ang pagbabagong ito ay mangyayari agad. Sigurado ka bang nais mong i-disconnect ang iyong account?" Basic.AutoConfig.StreamPage.GetStreamKey="Ang susi ng iyong stream" +Basic.AutoConfig.StreamPage.MoreInfo="Karagdagang Impormasyon" Basic.AutoConfig.StreamPage.UseStreamKey="Gumamit ang Stream key" Basic.AutoConfig.StreamPage.Service="Serbisyo" Basic.AutoConfig.StreamPage.Service.ShowAll="Ipakita lahat..." @@ -231,12 +233,12 @@ QuickTransitions.SwapScenesTT="Pinagpapalit ang mga pribyu at bunga na eksena ma QuickTransitions.DuplicateScene="Doblehin ang Eksena" QuickTransitions.DuplicateSceneTT="Kapag ineedit ang parehas na eksena, pinapayagan ang pagbabago ng anyo/kakayahang makita ng mga bukal nang hindi binabago ang bunga.\nPara mabago ang mga katangian ng mga bukal nang hindi binabago ang bunga, paganahin ang 'Doblehin ang mga Bukal'.\nMare-reset ang kasalukuyang eksenang bunga kapag binago ito (kung ito ay umiiral pa rin)." QuickTransitions.EditProperties="Gayahin ang mga pinagmulang" -QuickTransitions.EditPropertiesTT="Kung mag i-edit ng kaparehas na eksena. payagan mag edit ng katangian ng mga pinagkukunan nang hindi binabago ang output.\nIto ay magagamit king 'Duplicate Scene' ay pinagana.\nAng mga pinagkukunan(gaya ng nakuhang media sources) hindi suportado at di pwede ma edit nang hiwalay.\nAng pagbago ng value nito ay maaaring ma reset ang kasulukuyang output scene(kung mayroon pa).\n\nBabala: Dahil sa pinagkukunan ay magiging doble, ito ay nangangailangan ng ekstrang sistema or video pagkukunan." +QuickTransitions.EditPropertiesTT="Kapag binabago ang kaparehong eksena, pinapayagang baguhin ang mga katangian ng mga source na hindi binabago ang output.\nMagagamit lang ito kung ang 'Doblehin ang Eksena' ay naka-enable.\nAng ilang mga source (gaya ng mga capture at media source) ay hindi ito suportado at di pwede mababago nang hiwalay.\nAng pagbago ng value nito ay magrereset ng kasulukuyang eksenang output (kung mayroon pa).\n\nBabala: Dahil ang mga source ay magiging doble, maaaring mangailangan ito ng dagdag na resources ng sistema o video." QuickTransitions.HotkeyName="Ilipat ng mabilis: %1" Basic.AddTransition="Magdagdag ng configurable na transisyon" Basic.RemoveTransition="Tangalin ang configurable transition" -Basic.TransitionProperties="Mga Properties ng Transisyon" +Basic.TransitionProperties="Mga Katangian ng Transisyon" Basic.SceneTransitions="Pagbabago ng mga Eksena" Basic.TransitionDuration="Katagalan" Basic.TogglePreviewProgramMode="Ang Studio Mode" @@ -285,6 +287,8 @@ Output.ConnectFail.InvalidStream="Di maka pasok sa tinutukoy na channel or strea Output.ConnectFail.Error="Isang di-inaasahang error ng subukang kumunekta sa serber. Karagdagang impormasyon ay nasa log file." Output.ConnectFail.Disconnected="Nadiskonek mula sa serber." +Output.StreamEncodeError.Title="May error sa pag-encode" +Output.StreamEncodeError.Msg="Mayroong error ang lumabas habang ikaw ay nag-si-stream." Output.RecordFail.Title="Bigong simulang ang pag record" Output.RecordFail.Unsupported="Ang output format ay maaring di suportado or di sinusuportahan ang higit sa isang audio track. Pakitingnan ang iyong settings at simulan ulet." @@ -292,6 +296,7 @@ Output.RecordNoSpace.Title="Hindi sapat ang iyong espasyo" Output.RecordNoSpace.Msg="Di sapat ang espasyo para ipatuloy ang pagrerekord." Output.RecordError.Title="May error sa pagrekord" Output.RecordError.Msg="Hindi tiyak na error habang nagrerekord." +Output.RecordError.EncodeErrorMsg="Mayroong error ang lumabas habang ikaw ay nag-re-rekord." Output.BadPath.Title="Di mabuting File Path" Output.BadPath.Text="Ang na configured na file output path ay di di-wasto. Pakitignan ang iyong settings para ma kumpirma na balido ang file path at na i-set ito." @@ -333,6 +338,7 @@ Basic.DisplayCapture="Ang nakunan na display" Basic.Main.PreviewConextMenu.Enable="Ipakita muli ang Larawan" +Basic.Main.Preview.Disable="Di-pinagana ang Preview" ScaleFiltering="I-filter iskala" ScaleFiltering.Point="Punto" @@ -353,10 +359,8 @@ Deinterlacing.Yadif2x="Yadif 2x" Deinterlacing.TopFieldFirst="Pang unang itaas na field" Deinterlacing.BottomFieldFirst="Pang unang ibaba na field" -VolControl.SliderUnmuted="Pandausdos ng volume para '%1': %2" -VolControl.SliderMuted="Pandausdos ng volume para '%1': %2 (kasulukuyang naka mute)" VolControl.Mute="Mute '%1'" -VolControl.Properties="Mga katangian '%1'" +VolControl.Properties="Mga Katangian para sa '%1'" Basic.Main.AddSceneDlg.Title="Magdagdag ng mga Eksena" Basic.Main.AddSceneDlg.Text="Pakilagay ang pangalan ng eksena" @@ -384,7 +388,9 @@ Basic.SourceSelect.CreateNew="Gumawa ng bago" Basic.SourceSelect.AddExisting="Magdagdag ng Umiiral na" Basic.SourceSelect.AddVisible="Gawing nakikita ang mapagkukunan" -Basic.PropertiesWindow="Mga Properties para sa '%1'" + +Basic.PropertiesWindow="Mga Katangian para sa '%1'" +Basic.PropertiesWindow.AutoSelectFormat="%1 (awtomatikang-pagpili: %2)" Basic.PropertiesWindow.SelectColor="Pumili ng kulay" Basic.PropertiesWindow.SelectFont="Piliin ang font" Basic.PropertiesWindow.ConfirmTitle="Binago ang Mga Setting" @@ -400,7 +406,7 @@ Basic.PropertiesWindow.EditEditableListEntry="I-edit ang entry mula sa '%1'" Basic.PropertiesView.FPS.Simple="Mga Simpleng FPS na Halaga" Basic.PropertiesView.FPS.Rational="Mga Rational Value FPS" -Basic.PropertiesView.FPS.ValidFPSRanges="Mga saklaw na wastong FPS:" +Basic.PropertiesView.FPS.ValidFPSRanges="Mga wastong saklaw ng FPS:" Basic.InteractionWindow="Nakikisalamuha... '%1'" @@ -457,6 +463,7 @@ Basic.Main.Controls="Mga kontrol" Basic.Main.Connecting="Kumukonekta..." Basic.Main.StartRecording="Simula ng Pagtatala" Basic.Main.StartReplayBuffer="Simulan na ang pag Replay Buffer" +Basic.Main.SaveReplay="I-save ang Replay" Basic.Main.StartStreaming="Simulan ang mag stream" Basic.Main.StartVirtualCam="Simulan ang Virtual Camera" Basic.Main.StopRecording="Itigil ang Pagtatala" @@ -474,6 +481,8 @@ Basic.Main.StopVirtualCam="Itigil ang Virtual Camera" Basic.Main.Group="Grupo %1" Basic.Main.GroupItems="I-grupo ang napiling mga aytem" Basic.Main.Ungroup="Alisin sa Grupo" +Basic.Main.GridMode="Grid na Paraan" +Basic.Main.ListMode="Listahang Paraan" Basic.MainMenu.File="Talaksan (&F)" Basic.MainMenu.File.Export="I-&export" @@ -525,6 +534,7 @@ Basic.MainMenu.View.Docks.ResetUI="I-reset ang UI" Basic.MainMenu.View.Docks.LockUI="I-lock ang UI" Basic.MainMenu.View.ListboxToolbars="Listahan ng Pindutan ng Eksena/Bukal" Basic.MainMenu.View.SceneTransitions="Pagbabagong Eksena (&c)" +Basic.MainMenu.View.SourceIcons="Source &Icons" Basic.MainMenu.View.StatusBar="&Status bar" Basic.MainMenu.View.Fullscreen.Interface="Fullscreen Interface" @@ -549,6 +559,7 @@ Basic.MainMenu.Help.Logs.UploadCurrentLog="Mag-upload Kasalukuyang Mag-log ng Fi Basic.MainMenu.Help.Logs.UploadLastLog="Mag-up&load Huling pagla-log ng File" Basic.MainMenu.Help.Logs.ViewCurrentLog="Tignan ang Kasalukuyang pagla-log (&V)" Basic.MainMenu.Help.CheckForUpdates="Maghanap ng mga Update" +Basic.MainMenu.Help.CrashLogs.ShowLogs="&Ipakita ang Humintong Balita" Basic.MainMenu.Help.About="&Tungkol" Basic.Settings.ProgramRestart="Ang mga programa ay dapat na-restart para sa mga maaapektuhan na setting." @@ -579,9 +590,11 @@ Basic.Settings.General.SysTrayWhenStarted="Magbawas sa bandehadong sistema kapag Basic.Settings.General.SystemTrayHideMinimize="Palaging magbawas sa bandehadong sistema sa halip na task bar" Basic.Settings.General.SaveProjectors="I-save ang mga prodyektor sa labasan" Basic.Settings.General.Preview="Pribyu" +Basic.Settings.General.Importers="Mga taga-import" Basic.Settings.General.AutomaticCollectionSearch="Maghanap sa mga kilalang lugar para sa mga koleksyon ng eksena kapag nag-aangkat" Basic.Settings.General.SwitchOnDoubleClick="Lumipat sa eksena kapag nakadalawang-pindot" Basic.Settings.General.StudioPortraitLayout="Paganahin ang larawan/vertical layout" +Basic.Settings.General.Multiview="Kadaming-pagtingin" Basic.Settings.General.Multiview.MouseSwitch="Pindutin para lumipat sa mga eksena" Basic.Settings.General.Multiview.DrawSourceNames="Ipakita ang mga pangalan ng eksena" Basic.Settings.General.MultiviewLayout="Multiview Layout" @@ -605,7 +618,6 @@ Basic.Settings.Output.Format="Pagtatala ng recording" Basic.Settings.Output.Encoder="Encoder" Basic.Settings.Output.SelectDirectory="Piliin ang direktoryong pagtatala" Basic.Settings.Output.SelectFile="Piliin ang file ng pagtatala" -Basic.Settings.Output.EnforceBitrate="Ipatupad ang serbisyo ng limitadong bitrate" Basic.Settings.Output.Mode="Uri ng Pagbunga" Basic.Settings.Output.Mode.Simple="Simple" Basic.Settings.Output.Mode.Adv="Pagsulong" @@ -622,7 +634,6 @@ Basic.Settings.Output.Simple.RecordingQuality.Stream="Parehong stream" Basic.Settings.Output.Simple.RecordingQuality.Small="Mataas na Kalidad, Katamtamang Laki ng File" Basic.Settings.Output.Simple.RecordingQuality.HQ="Indistinguishable Quality, Large File Size" Basic.Settings.Output.Simple.RecordingQuality.Lossless="Lossless Quality, Napakalaki ng Laki ng File" -Basic.Settings.Output.Simple.Warn.VideoBitrate="Babala: Ang bitrate ng streaming video ay itatakda sa%1, na kung saan ay ang itaas na limitasyon para sa kasalukuyang streaming service. Kung sigurado ka na gusto mong pumunta sa itaas%1, paganahin ang mga advanced na mga pagpipilian sa encoder at alisan ng tsek ang \"Ipatupad ang mga limitasyong bitrate ng service streaming\"." Basic.Settings.Output.Simple.Warn.Encoder="Babala: Ang pagrekord sa isang encoder ng software sa ibang kalidad kaysa sa stream ay mangangailangan ng dagdag na paggamit ng CPU kung mag-stream at mag-record ka sa parehong oras." Basic.Settings.Output.Simple.Warn.Lossless="Babala: Hindi mawawalan ng kalidad ang bumubuo ng napakalaking malalaking sukat ng file! Maaaring gumamit ng walang humpay na kalidad ng hanggang 7 gigabytes ng puwang ng disk kada minuto sa mataas na resolution at framerates. Ang hindi nawawala ay hindi inirerekomenda para sa mahabang pag-record maliban kung mayroon kang isang napakalaking halaga ng disk space na magagamit." Basic.Settings.Output.Simple.Warn.Lossless.Msg="Sigurado ka bang gusto mong gumamit ng kalidad na walang pagkawala?" @@ -644,7 +655,6 @@ Basic.Settings.Output.NoSpaceFileName="Bumuo ng Pangalan ng File nang walang Spa Basic.Settings.Output.Adv.Rescale="Rescale Output" Basic.Settings.Output.Adv.AudioTrack="Audio Track" Basic.Settings.Output.Adv.Streaming="Streaming" -Basic.Settings.Output.Adv.ApplyServiceSettings="Ipatupad ang mga setting ng encoder ng streaming service" Basic.Settings.Output.Adv.Audio.Track1="Subaybayan ang 1" Basic.Settings.Output.Adv.Audio.Track2="Subaybayan ang 2" Basic.Settings.Output.Adv.Audio.Track3="Subaybayan ang 3" @@ -656,7 +666,7 @@ Basic.Settings.Output.Adv.Recording="Pagre-record" Basic.Settings.Output.Adv.Recording.Type="Uri" Basic.Settings.Output.Adv.Recording.Type.Standard="Standard" Basic.Settings.Output.Adv.Recording.Type.FFmpegOutput="Custom Output (FFmpeg)" -Basic.Settings.Output.Adv.Recording.UseStreamEncoder="(Gamitin ang stream encoder)" +Basic.Settings.Output.Adv.Recording.UseStreamEncoder="(Gamitin ang encoder para sa stream)" Basic.Settings.Output.Adv.Recording.Filename="Pag-format ng Filename" Basic.Settings.Output.Adv.Recording.OverwriteIfExists="I-overwrite kung umiiral ang file" Basic.Settings.Output.Adv.FFmpeg.Type="FFmpeg Output Type" @@ -683,6 +693,7 @@ Basic.Settings.Output.Adv.FFmpeg.IgnoreCodecCompat="Ipakita lahat ng codecs (kah Screenshot.Scene="Kuha ng Screen (Eksena)" +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\n%FPS\n%CRES\n%ORES\n%VF" Basic.Settings.Video="Bidyo" @@ -709,9 +720,12 @@ Basic.Settings.Video.DownscaleFilter.Lanczos="Lanczos (Sharpened scaling, 36 mga Basic.Settings.Audio="Tunog" Basic.Settings.Audio.SampleRate="Halimbawa ng Antas" Basic.Settings.Audio.Channels="Mga Channel" +Basic.Settings.Audio.Meters="Mga Metro" +Basic.Settings.Audio.MeterDecayRate="Bilis ng Pagkupas" Basic.Settings.Audio.MeterDecayRate.Fast="Pabilisin" Basic.Settings.Audio.MeterDecayRate.Medium="Katamtaman (Tipo I PPM)" Basic.Settings.Audio.MeterDecayRate.Slow="Mabagal (Tipo II PPM)" +Basic.Settings.Audio.PeakMeterType="Uri ng Tuktok ng Metro" Basic.Settings.Audio.MultiChannelWarning.Enabled="Babala: Ang Surround sound audio ay naka andar." Basic.Settings.Audio.MultichannelWarning.Title="Paganahin ang surround sound audio?" Basic.Settings.Audio.MultichannelWarning.Confirm="Sigurado ka ba gusto mong paganahin ang surround sound audio?" @@ -720,6 +734,7 @@ Basic.Settings.Audio.PushToMuteDelay="Push-to-mute delay" Basic.Settings.Audio.EnablePushToTalk="Paganahin ang Push-to-talk" Basic.Settings.Audio.PushToTalkDelay="Push-to-talk delay" Basic.Settings.Audio.UnknownAudioDevice="[Hindi konektado o hindi magagamit ang device]" +Basic.Settings.Audio.Disabled="Di-napagana" Basic.Settings.Advanced="Advanced" Basic.Settings.Advanced.General.ProcessPriority="Prayoridad sa Proseso" @@ -731,8 +746,11 @@ Basic.Settings.Advanced.General.ProcessPriority.Idle="Walang ginagawa" Basic.Settings.Advanced.FormatWarning="Babala: Ang mga format ng kulay maliban sa NV12 ay pangunahing inilaan para sa pag-record, at hindi inirerekomenda kapag nag-stream. Maaaring mapalawak ng streaming ang paggamit ng CPU dahil sa conversion ng format ng kulay." Basic.Settings.Advanced.Audio.BufferingTime="Audio Buffering Time" Basic.Settings.Advanced.Video.ColorFormat="Format ng Kulay" +Basic.Settings.Advanced.Video.ColorSpace="Espasyo ng Kulay" +Basic.Settings.Advanced.Video.ColorRange="Lawak ng Kulay" Basic.Settings.Advanced.Video.ColorRange.Partial="Bahagyang" Basic.Settings.Advanced.Video.ColorRange.Full="Buo" +Basic.Settings.Advanced.Audio.MonitoringDevice="Tagapayong Aparato" Basic.Settings.Advanced.Audio.MonitoringDevice.Default="I-Default" Basic.Settings.Advanced.Audio.DisableAudioDucking="Huwag paganahin ang Windows audio ducking" Basic.Settings.Advanced.StreamDelay="Ang Antala ng Stream" @@ -741,9 +759,18 @@ Basic.Settings.Advanced.StreamDelay.Preserve="Ingatang ang cutoff point (pataas Basic.Settings.Advanced.StreamDelay.MemoryUsage="Ang na estimang nagamit na memorya: %1 MB" Basic.Settings.Advanced.Network="Network" Basic.Settings.Advanced.Network.BindToIP="Ibigkis sa IP" +Basic.Settings.Advanced.Hotkeys.HotkeyFocusBehavior="Ugali ng Pokus ng Hotkey" +Basic.Settings.Advanced.Hotkeys.NeverDisableHotkeys="Huwag i-pagana ang hotkeys" +Basic.Settings.Advanced.Hotkeys.DisableHotkeysInFocus="Di-pinagana ang hotkeys kung ang main window ay nasa fokus" +Basic.Settings.Advanced.Hotkeys.DisableHotkeysOutOfFocus="Di-pinagana ang hotkeys kung ang main window ay hindi nasa fokus" +Basic.Settings.Advanced.AutoRemux="Awtomatikang remux sa mp4" +Basic.Settings.Advanced.AutoRemux.MP4="(i-rekord bilang mkv)" Basic.AdvAudio="Ang aria-arian ng Advanced Audio" +Basic.AdvAudio.ActiveOnly="Lamang Actibong Sources" Basic.AdvAudio.Name="Pangalan" +Basic.AdvAudio.Volume="Tunog" +Basic.AdvAudio.Mono="Mono" Basic.AdvAudio.Balance="Balanse" Basic.AdvAudio.Monitoring="Ang subaybay ng Audio" Basic.AdvAudio.Monitoring.None="I-Off ang Monitor" @@ -753,6 +780,7 @@ Basic.AdvAudio.AudioTracks="Mga Tracks" Basic.Settings.Hotkeys="Ang mga Hotkeys" Basic.Settings.Hotkeys.Pair="Ang nabahaging kombinasyon ng susi na may '%1' akto sa toggles" +Basic.Settings.Hotkeys.Filter="Salain" Basic.Hotkeys.SelectScene="Lumipat sa eksena" @@ -796,6 +824,7 @@ Hotkeys.AppleKeypadSubtract="- (Keypad)" Hotkeys.AppleKeypadDecimal=". (Keypad)" Hotkeys.AppleKeypadEqual="= (Keypad)" Hotkeys.MouseButton="Mouse %1" +Hotkeys.Escape="Esc" Mute="I-Mute" Unmute="I-Unmute" @@ -806,16 +835,29 @@ SceneItemShow="Ipakita ang '%1'" SceneItemHide="Itago ang '%1'" OutputWarnings.NoTracksSelected="Dapat pumili ka ng kahit isang track" +OutputWarnings.MP4Recording="Babala: Ang mga rekord na naka-save sa MP4/MOV ay hindi na mababawi kung ang file ay hindi natapos (hal. dulot ng BSODs, pagkawala ng kuryente, atbp.). Kung nais mong magrekord ng maraming audio tracks, isaalang-alang ang paggamit ng MKV at i-remux ang recording sa MP4/MOV pagkatapos nitong matapos (File → Remux Recordings)" +OutputWarnings.CannotPause="Babala: Ang pagrerekord ay hindi mapapahintong sandali kung ang encoder sa pagrerekord ay nakatakda sa \"(Gamitin ang encoder para sa stream)\"" FinalScene.Title="Tanggal-Eksena" FinalScene.Text="Kailangang mayroong kahit isang eksena." +NoSources.Title="Walang Sources" +NoSources.Label="Walang kang mga sources. \nPindutin mo ang + button sa baba,\no kanang-pindutan mo dito upang magdagdag ng isa." +ChangeBG="I-takda ang Kulay" +CustomColor="Pasadyang Kulay" About="Tungkol dito" +About.Info="Ang OBS Studio ay isang libre at open source na software para sa parerercord ng bidyo at pag-iistream nang live." +About.Donate="Tumulong" +About.GetInvolved="Makisali" +About.Authors="Mga Nag-gawa" About.License="Lisensya" +About.Contribute="I-suporta ang OBS Project" +AddUrl.Title="Magdagdag ng Source gamit ang URL" +AddUrl.Text="Hinila mo ang isang URL papunta sa OBS. Kusang madaragdag ang link bilang isang source. Tuloy?" AddUrl.Text.Url="URL: %1" ResizeOutputSizeOfSource.Continue="Gusto mo bang magpatuloy?" @@ -824,11 +866,22 @@ ResizeOutputSizeOfSource.Continue="Gusto mo bang magpatuloy?" Importer="Pang-angkat ng Koleksyon ng Eksena" Importer.SelectCollection="Pumili ng Koleksyon ng Eksena" Importer.Collection="Koleksyon ng Eksena" +Importer.HelpText="Magdagdag ng mga file sa window na ito upang mag-angkat ng mga koleksyon mula sa OBS o sa ibang mga suportadong program." Importer.AutomaticCollectionPrompt="Awtomatikong Maghanap ng mga Koleksyon ng Eksena" Importer.AutomaticCollectionText="Kaya ng OBS na kusang maghanap ng maaangkas na koleksyon ng eksena mula sa mga suportadong third-party program. Nais mo bang kusang maghanap ng mga koleksyon ang OBS para sa iyo?\n\nMaaari mo itong palitan mamaya sa Settings > General > Importers." Restart="I-restart" +ContextBar.NoSelectedSource="Walang piniling source" +ContextBar.ResetTransform="I-reset ang Pag-transform" +ContextBar.FitToCanvas="Ayusin sa Canvas" +ContextBar.MediaControls.PlayMedia="Maglaro ng Media" +ContextBar.MediaControls.PauseMedia="I-pause ang Media" +ContextBar.MediaControls.StopMedia="I-tigil ang Media" +ContextBar.MediaControls.RestartMedia="Ulitin ang Media" +ContextBar.MediaControls.PlaylistNext="Kasunod sa Playlist" +ContextBar.MediaControls.PlaylistPrevious="Nakaraan sa Playlist" +ContextBar.MediaControls.MediaProperties="Mga Katangian ng Media" diff --git a/UI/data/locale/fr-FR.ini b/UI/data/locale/fr-FR.ini index 245e1ba..d9afb04 100644 --- a/UI/data/locale/fr-FR.ini +++ b/UI/data/locale/fr-FR.ini @@ -161,6 +161,7 @@ Basic.AutoConfig.StreamPage.DisconnectAccount="Déconnecter le compte" Basic.AutoConfig.StreamPage.DisconnectAccount.Confirm.Title="Déconnecter le compte ?" Basic.AutoConfig.StreamPage.DisconnectAccount.Confirm.Text="Cette modification s'appliquera immédiatement. Êtes-vous sûr de vouloir déconnecter votre compte ?" Basic.AutoConfig.StreamPage.GetStreamKey="Récupérer la clé de stream" +Basic.AutoConfig.StreamPage.MoreInfo="Plus d'info" Basic.AutoConfig.StreamPage.UseStreamKey="Utiliser la clé de stream" Basic.AutoConfig.StreamPage.Service="Service" Basic.AutoConfig.StreamPage.Service.ShowAll="Afficher tout..." @@ -365,8 +366,8 @@ Deinterlacing.Yadif2x="Yadif 2x" Deinterlacing.TopFieldFirst="Champ du haut prioritaire" Deinterlacing.BottomFieldFirst="Champ du bas prioritaire" -VolControl.SliderUnmuted="Curseur de volume pour '%1': %2" -VolControl.SliderMuted="Curseur de volume pour '%1' : %2 (actuellement muet)" +VolControl.SliderUnmuted="Curseur de volume pour \"%1\":" +VolControl.SliderMuted="Curseur de volume pour \"%1\": (actuellement muet)" VolControl.Mute="Muet '%1'" VolControl.Properties="Propriétés pour '%1'" @@ -382,6 +383,7 @@ Basic.Main.RenameSceneCollection.Title="Renommer la collection de scènes" AddProfile.Title="Ajouter un profil" AddProfile.Text="Veuillez entrer le nom du profil" +AddProfile.WizardCheckbox="Afficher l'assistant de configuration automatique" RenameProfile.Title="Renommer le profil" @@ -396,6 +398,11 @@ Basic.SourceSelect.CreateNew="Créer une nouvelle source" Basic.SourceSelect.AddExisting="Ajouter une source existante" Basic.SourceSelect.AddVisible="Rendre la source visible" +Basic.Main.Sources.Visibility="Visibilité" +Basic.Main.Sources.VisibilityDescription="Contrôle la visibilité de \"%1\" sur la toile" +Basic.Main.Sources.Lock="Verrouiller" +Basic.Main.Sources.LockDescription="Verrouille la position et la taille de \"%1\" sur la toile" + Basic.PropertiesWindow="Propriétés pour '%1'" Basic.PropertiesWindow.AutoSelectFormat="%1 (sélection automatique : %2)" Basic.PropertiesWindow.SelectColor="Sélectionner une couleur" @@ -635,13 +642,19 @@ Basic.Settings.Stream.StreamSettingsWarning="Ouvrir les paramètres" Basic.Settings.Stream.MissingUrlAndApiKey="L'URL et la clé de diffusion sont manquantes.\n\nOuvrez les paramètres et entrez l'URL et la clé de diffusion dans l'onglet Stream." Basic.Settings.Stream.MissingUrl="L'URL de diffusion est manquante.\n\nOuvrez les paramètres et entrez l'URL de diffusion dans l'onglet Stream." Basic.Settings.Stream.MissingStreamKey="La clé de diffusion est manquante.\n\nOuvrez les paramètres et entrez la clé de diffusion dans l'onglet Stream." +Basic.Settings.Stream.IgnoreRecommended="Ignorer les paramètres recommandés du service de streaming" +Basic.Settings.Stream.IgnoreRecommended.Warn.Title="Remplacer les paramètres recommandés" +Basic.Settings.Stream.IgnoreRecommended.Warn.Text="Attention : ignorer les limitations du service de diffusion peut entraîner une dégradation de la qualité du flux voir vous empêcher de diffuser.\n\nContinuer ?" +Basic.Settings.Stream.Recommended.MaxVideoBitrate="Débit vidéo maximal : %1 kbps" +Basic.Settings.Stream.Recommended.MaxAudioBitrate="Débit audio maximal : %1 kbps" +Basic.Settings.Stream.Recommended.MaxResolution="Résolution maximale: %1" +Basic.Settings.Stream.Recommended.MaxFPS="IPS Maximum: %1" Basic.Settings.Output="Sortie" Basic.Settings.Output.Format="Format d'enregistrement" Basic.Settings.Output.Encoder="Encodeur" Basic.Settings.Output.SelectDirectory="Sélectionnez le répertoire d'enregistrement" Basic.Settings.Output.SelectFile="Sélectionnez le fichier cible" -Basic.Settings.Output.EnforceBitrate="Imposer les limites de débit du service de streaming" Basic.Settings.Output.DynamicBitrate="Ajuster dynamiquement le débit de streaming en cas de congestion réseau" Basic.Settings.Output.DynamicBitrate.Beta="Ajuster dynamiquement le débit de streaming en cas de congestion réseau (Beta)" Basic.Settings.Output.DynamicBitrate.TT="Ajuste automatiquement le débit de streaming pour éviter les pertes d'images en cas de congestion ou de surcharge réseau.\n\nCela peut augmenter le délai entre vous et vos spectateurs si la congestion est significative.\nQuand le débit est réduit automatiquement, plusieurs minutes peuvent s'écouler avant qu'il ne revienne à la normale.\n\nN'est supporté que pour RTMP pour l'instant." @@ -662,8 +675,8 @@ Basic.Settings.Output.Simple.RecordingQuality.Stream="Identique au stream" Basic.Settings.Output.Simple.RecordingQuality.Small="Haute qualité, taille de fichier moyenne" Basic.Settings.Output.Simple.RecordingQuality.HQ="Qualité indistinguable, grande taille de fichier " Basic.Settings.Output.Simple.RecordingQuality.Lossless="Qualité sans perte, énorme taille de fichier" -Basic.Settings.Output.Simple.Warn.VideoBitrate="Attention: le débit vidéo de streaming va être fixé à %1, qui est la limite maximale pour le service de streaming actuel. Si vous êtes surs de vouloir aller au delà de %1, activez les options avancées de l'encodeur & décochez \"Imposer les limites de débit du service de streaming\"." -Basic.Settings.Output.Simple.Warn.AudioBitrate="Attention: le débit audio de streaming va être fixé à %1, qui est la limite maximale pour le service de streaming actuel. Si vous êtes surs de vouloir aller au delà de %1, activez les options avancées de l'encodeur & décochez \"Imposer les limites de débit du service de streaming\"." +Basic.Settings.Output.Simple.Warn.VideoBitrate="Attention : le débit vidéo de la diffusion sera réglé à %1, ce qui est la valeur maximale pour le service de diffusion actuel." +Basic.Settings.Output.Simple.Warn.AudioBitrate="Attention : le débit audio de la diffusion sera réglé à %1, ce qui est la valeur maximale pour le service de diffusion actuel." Basic.Settings.Output.Simple.Warn.CannotPause="Attention : l'enregistrement ne peut pas être mis en pause si la qualité d'enregistrement est configurée sur \"Identique au stream\"." Basic.Settings.Output.Simple.Warn.Encoder="Attention : enregistrer via un encodeur logiciel avec une qualité autre que celle du stream sollicitera encore plus le CPU si vous streamez et enregistrez simultanément." Basic.Settings.Output.Simple.Warn.Lossless="Attention: la qualité sans perte génère des fichiers de taille énorme ! Elle peut utiliser jusqu'à 7 gigaoctets d'espace disque par minute pour de hautes résolutions et fréquences d'image. Cette qualité n'est pas recommandée pour de longs enregistrements à moins d'avoir énormément d'espace disque disponible." @@ -674,6 +687,11 @@ 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.Simple.TwitchVodTrack="Piste de VOD Twitch (utilise la piste 2)" +Basic.Settings.Output.Warn.EnforceResolutionFPS.Title="Résolution/Framerate incompatible" +Basic.Settings.Output.Warn.EnforceResolutionFPS.Msg="Ce service de streaming ne prend pas en charge la résolution de sortie et/ou le framerate actuel. Ils seront modifiés à la valeur compatible la plus proche : \n\n%1\n\n Voulez vous continuer ?" +Basic.Settings.Output.Warn.EnforceResolutionFPS.Resolution="Résolution: %1" +Basic.Settings.Output.Warn.EnforceResolutionFPS.FPS="FPS: %1" Basic.Settings.Output.VideoBitrate="Débit vidéo" Basic.Settings.Output.AudioBitrate="Débit audio" Basic.Settings.Output.Reconnect="Reconnexion automatique" @@ -688,15 +706,16 @@ Basic.Settings.Output.NoSpaceFileName="Générer le nom du fichier sans espace" Basic.Settings.Output.Adv.Rescale="Mise à l'échelle pour la Sortie" Basic.Settings.Output.Adv.AudioTrack="Piste audio" Basic.Settings.Output.Adv.Streaming="Streaming" -Basic.Settings.Output.Adv.ApplyServiceSettings="Imposer les paramètres d'encodage du service de streaming" Basic.Settings.Output.Adv.Audio.Track1="Piste 1" Basic.Settings.Output.Adv.Audio.Track2="Piste 2" Basic.Settings.Output.Adv.Audio.Track3="Piste 3" Basic.Settings.Output.Adv.Audio.Track4="Piste 4" Basic.Settings.Output.Adv.Audio.Track5="Piste 5" Basic.Settings.Output.Adv.Audio.Track6="Piste 6" +Basic.Settings.Output.Adv.TwitchVodTrack="Piste VOD Twitch" Basic.Settings.Output.Adv.Recording="Enregistrement" +Basic.Settings.Output.Adv.Recording.RecType="Type d'enregistrement" Basic.Settings.Output.Adv.Recording.Type="Type " Basic.Settings.Output.Adv.Recording.Type.Standard="Standard" Basic.Settings.Output.Adv.Recording.Type.FFmpegOutput="Sortie Personnalisée (FFmpeg)" @@ -824,13 +843,18 @@ Basic.AdvAudio="Propriétés Audio Avancées" Basic.AdvAudio.ActiveOnly="Sources actives uniquement" Basic.AdvAudio.Name="Nom" Basic.AdvAudio.Volume="Volume" +Basic.AdvAudio.VolumeSource="Volume pour \"%1\"" Basic.AdvAudio.Mono="Mono" +Basic.AdvAudio.MonoSource="Conversion en mono pour \"%1\"" Basic.AdvAudio.Balance="Balance" +Basic.AdvAudio.BalanceSource="Balance audio pour \"%1\"" Basic.AdvAudio.SyncOffset="Décalage de synchronisation" +Basic.AdvAudio.SyncOffsetSource="Décalage de synchronisation pour \"%1\"" Basic.AdvAudio.Monitoring="Monitoring Audio" Basic.AdvAudio.Monitoring.None="Monitoring Désactivé" Basic.AdvAudio.Monitoring.MonitorOnly="Monitoring uniquement (couper la sortie)" Basic.AdvAudio.Monitoring.Both="Monitoring et Sortie" +Basic.AdvAudio.MonitoringSource="Monitoring audio pour \"%1\"" Basic.AdvAudio.AudioTracks="Pistes" Basic.Settings.Hotkeys="Raccourcis clavier" diff --git a/UI/data/locale/gd-GB.ini b/UI/data/locale/gd-GB.ini index 7bf6eeb..7c0a511 100644 --- a/UI/data/locale/gd-GB.ini +++ b/UI/data/locale/gd-GB.ini @@ -341,8 +341,6 @@ Deinterlacing.Yadif2x="Yadif 2x" Deinterlacing.TopFieldFirst="An raon air a’ bharr an toiseach" Deinterlacing.BottomFieldFirst="An raon aig a’ bhonn an toiseach" -VolControl.SliderUnmuted="Sleamhnachan àirde airson “%1”: %2" -VolControl.SliderMuted="Sleamhnachan àirde airson “%1”: %2 (mùchte an-dràsta)" VolControl.Mute="Mùch “%1”" VolControl.Properties="Roghainnean airson “%1”" @@ -372,6 +370,7 @@ Basic.SourceSelect.CreateNew="Cruthaich tùs ùr" Basic.SourceSelect.AddExisting="Cuir ris tùs a tha ann" Basic.SourceSelect.AddVisible="Seall an tùs" + Basic.PropertiesWindow="Roghainnean airson “%1”" Basic.PropertiesWindow.AutoSelectFormat="%1 (taghadh fèin-obrachail: %2)" Basic.PropertiesWindow.SelectColor="Tagh dath" @@ -597,7 +596,6 @@ Basic.Settings.Output.Format="Fòrmat a’ chlàraidh" Basic.Settings.Output.Encoder="Inneal-còdachaidh" Basic.Settings.Output.SelectDirectory="Tagh pasgan a’ chlàraidh" Basic.Settings.Output.SelectFile="Tagh faidhle clàraidh" -Basic.Settings.Output.EnforceBitrate="Èignich cuingeachaidhean reat bhiotaichean aig an t-seirbheis sruthaidh" Basic.Settings.Output.DynamicBitrate="Atharraich an reat bhiotaichean gu h-innsgineach a sheachnadh dùmhlachd" Basic.Settings.Output.DynamicBitrate.Beta="Atharraich an reat bhiotaichean gu h-innsgineach a sheachnadh dùmhlachd (Beta)" Basic.Settings.Output.DynamicBitrate.TT="Atharraichidh seo an reat bhiotaichean seach tuiteam fhrèamaichean nuair a bhios dùmhlachd ann.\n\nThoir an aire gum bi barrachd dàil air dhan amharc ma dh’fhaoidte ma thachras dùmhlachd gu h-obann.\nNuair a thuiteas an reat bhiotaichean, dh’fhaoidte gun toir e mionaid no dhà mus dèid a shlànachadh.\n\nCha chuir sinn taic ach ri RTMP aig an àm seo." @@ -618,8 +616,6 @@ Basic.Settings.Output.Simple.RecordingQuality.Stream="Co-ionnann ri tè an t-sru Basic.Settings.Output.Simple.RecordingQuality.Small="Càileachd àrd, faidhle meadhanach mòr" Basic.Settings.Output.Simple.RecordingQuality.HQ="Cha ghabh diofar aithneachadh, faidhle mòr" Basic.Settings.Output.Simple.RecordingQuality.Lossless="Càileachd gun chall, faidhle uabhasach mòr" -Basic.Settings.Output.Simple.Warn.VideoBitrate="Rabhadh: Thèid reat bhiotaichean video an t-sruthaidh a shuidheachadh air %1, seo a’ chrìoch as àirde aig an t-seirbheis sruthaidh làithreach. Ma tha thu cinnteach bu bheil thu airson corr is %1 a chleachdadh, cuir an comas roghainnean adhartach an inneil-chòdachaidh agus thoir a’ chromag far “Èignich cuingeachaidhean reat bhiotaichean aig an t-seirbheis sruthaidh”." -Basic.Settings.Output.Simple.Warn.AudioBitrate="Rabhadh: Thèid reat bhiotaichean fuaime an t-sruthaidh a shuidheachadh air %1, seo a’ chrìoch as àirde aig an t-seirbheis sruthaidh làithreach. Ma tha thu cinnteach bu bheil thu airson corr is %1 a chleachdadh, cuir an comas roghainnean adhartach an inneil-chòdachaidh agus thoir a’ chromag far “Èignich cuingeachaidhean reat bhiotaichean aig an t-seirbheis sruthaidh”." Basic.Settings.Output.Simple.Warn.CannotPause="Rabhadh: Cha ghabh clàradh a chur ’na stad nuair a bhios càileachd “Co-ionnann ri tè an t-sruthaidh” air a’ chlàradh." Basic.Settings.Output.Simple.Warn.Encoder="Rabhadh: Ma nì thu clàradh le inneal-còdachaidh bathair-bhog air nach eil an aon chàileachd ’s a th’ air an t-sruthadh, bi feum air barrachd cleachdadh a’ CPU nuair a bhios tu a’ sruthadh ’s a’ clàradh aig an aon àm." Basic.Settings.Output.Simple.Warn.Lossless="Rabhadh: Cruthaichidh càileachd gun chall faidhlichean uabhasach mòr! Faodaidh càileachd gun chall corr is 7 giga-baidht a dh’àite a chleachdadh air an diosg gach mionaid ma tha an dùmhlachd-bhreacaidh agus an reat fhrèamaichean àrd. Cha mholamaid càileachd gun chall airson clàraidhean fada ach ma tha torr àite agad air an diosg." @@ -644,7 +640,6 @@ Basic.Settings.Output.NoSpaceFileName="Gin ainm faidhle gun spàs" Basic.Settings.Output.Adv.Rescale="Ath-sgèilich an t-às-chur" Basic.Settings.Output.Adv.AudioTrack="Traca fuaime" Basic.Settings.Output.Adv.Streaming="Sruthadh" -Basic.Settings.Output.Adv.ApplyServiceSettings="Èignich na roghainnean inneil-chòdachaidh aig an t-seirbheis sruthaidh" Basic.Settings.Output.Adv.Audio.Track1="Traca 1" Basic.Settings.Output.Adv.Audio.Track2="Traca 2" Basic.Settings.Output.Adv.Audio.Track3="Traca 3" diff --git a/UI/data/locale/gl-ES.ini b/UI/data/locale/gl-ES.ini index b5f6586..fa6e1c7 100644 --- a/UI/data/locale/gl-ES.ini +++ b/UI/data/locale/gl-ES.ini @@ -161,6 +161,7 @@ Basic.AutoConfig.StreamPage.DisconnectAccount="Desconectar a conta" Basic.AutoConfig.StreamPage.DisconnectAccount.Confirm.Title="Desconectar a conta?" Basic.AutoConfig.StreamPage.DisconnectAccount.Confirm.Text="Este cambio aplicarase de inmediato. Está seguro de que quere desconectar a súa conta?" Basic.AutoConfig.StreamPage.GetStreamKey="Obter a clave da emisión" +Basic.AutoConfig.StreamPage.MoreInfo="Máis Información" Basic.AutoConfig.StreamPage.UseStreamKey="Usar a clave da emisión" Basic.AutoConfig.StreamPage.Service="Servizo" Basic.AutoConfig.StreamPage.Service.ShowAll="Amosar todo..." @@ -365,8 +366,8 @@ Deinterlacing.Yadif2x="Yadif 2x" Deinterlacing.TopFieldFirst="Primeiro o campo superior" Deinterlacing.BottomFieldFirst="Primeiro o campo inferior" -VolControl.SliderUnmuted="Potenciómetro de volume para «%1»: %2" -VolControl.SliderMuted="Potenciómetro de volume para «%1»: %2 (actualmente silenciado)" +VolControl.SliderUnmuted="Potenciómetro de volume para «%1»:" +VolControl.SliderMuted="Potenciómetro de volume para «%1»: (actualmente silenciado)" VolControl.Mute="Silenciar «%1»" VolControl.Properties="Propiedades para «%1»" @@ -382,6 +383,7 @@ Basic.Main.RenameSceneCollection.Title="Renomear a colección de escenas" AddProfile.Title="Engadir perfil" AddProfile.Text="Insira o nome do perfil" +AddProfile.WizardCheckbox="Amosar o asistente de configuración automática" RenameProfile.Title="Renomear o perfil" @@ -396,6 +398,11 @@ Basic.SourceSelect.CreateNew="Crear nova" Basic.SourceSelect.AddExisting="Engadir existente" Basic.SourceSelect.AddVisible="Facer visíbel a fonte" +Basic.Main.Sources.Visibility="Visibilidade" +Basic.Main.Sources.VisibilityDescription="Controla a visibilidade de «%1» no lenzo" +Basic.Main.Sources.Lock="Bloquear" +Basic.Main.Sources.LockDescription="Bloquea a posición e escala de «%1» no lenzo" + Basic.PropertiesWindow="Propiedades para «%1»" Basic.PropertiesWindow.AutoSelectFormat="%1 (seleccionar automaticamente: %2)" Basic.PropertiesWindow.SelectColor="Seleccionar cor" @@ -635,13 +642,19 @@ Basic.Settings.Stream.StreamSettingsWarning="Abrir os axustes" Basic.Settings.Stream.MissingUrlAndApiKey="Non se atopa o URL e a clave da emisión.\n\nAbra os axustes para introducir o URL e a clave da emisión na lapela «Emisión»." Basic.Settings.Stream.MissingUrl="Non se atopa o URL.\n\nAbra os axustes para introducir o URL na lapela «Emisión»." Basic.Settings.Stream.MissingStreamKey="Non se atopa a clave da emisión.\n\nAbra os axustes para introducir a clave da emisión na lapela «Emisión»." +Basic.Settings.Stream.IgnoreRecommended="Ignorar as recomendacións de axuste do servizo de transmisión" +Basic.Settings.Stream.IgnoreRecommended.Warn.Title="Anular os axustes recomendados" +Basic.Settings.Stream.IgnoreRecommended.Warn.Text="Advertencia: ignorar as limitacións do servizo pode provocar unha degradación da calidade do fluxo ou impedir a transmisión.\n\nQuere continuar?" +Basic.Settings.Stream.Recommended.MaxVideoBitrate="Taxa máxima de bits de vídeo: %1 kbps" +Basic.Settings.Stream.Recommended.MaxAudioBitrate="Taxa máxima de bits de son: %1 kbps" +Basic.Settings.Stream.Recommended.MaxResolution="Resolución máxima: %1" +Basic.Settings.Stream.Recommended.MaxFPS="Taxa máxima de cadros por segundo: %1" Basic.Settings.Output="Saída" Basic.Settings.Output.Format="Formato de gravación" Basic.Settings.Output.Encoder="Codificador" Basic.Settings.Output.SelectDirectory="Seleccionar o directorio de gravación" Basic.Settings.Output.SelectFile="Seleccionar o ficheiro de gravación" -Basic.Settings.Output.EnforceBitrate="Aplicar os límites de taxa de bits do servizo de emisión" Basic.Settings.Output.DynamicBitrate="Cambiar dinamicamente a taxa de bits para xestionar a conxestión" Basic.Settings.Output.DynamicBitrate.Beta="Cambiar dinamicamente a taxa de bits para xestionar a conxestión (beta)" Basic.Settings.Output.DynamicBitrate.TT="No canto de deixar perder cadros para reducir a conxestión, cambia dinamicamente a taxa de bits.\n\nTeña en conta que isto pode aumentar o atraso para os espectadores se hai unha conxestión súbita importante.\n\n Cando a taxa de bits cae, pode tardar uns minutos en restaurarse.\n\nActualmente só é compatible con RTMP." @@ -662,8 +675,8 @@ Basic.Settings.Output.Simple.RecordingQuality.Stream="A mesma da emisión" Basic.Settings.Output.Simple.RecordingQuality.Small="Alta calidade, tamaño medio do ficheiro" Basic.Settings.Output.Simple.RecordingQuality.HQ="Calidade indistinguíbel, tamaño de ficheiro grande" Basic.Settings.Output.Simple.RecordingQuality.Lossless="Calidade sen perda, tamaño inmenso de ficheiro" -Basic.Settings.Output.Simple.Warn.VideoBitrate="Aviso: A taxa de bits do vídeo en emisión estabelecerase en %1, que é o límite superior para o servizo de emisión actual. Se está seguro de que quere superar %1, active as opcións avanzadas do codificador e desmarque «Aplicar os límites de taxa de bits do servizo de emisión»." -Basic.Settings.Output.Simple.Warn.AudioBitrate="Aviso: A taxa de bits do son en emisión estabelecerase en %1, que é o límite superior para o servizo deemisión actual. Se está seguro de que quere superar %1, active as opcións avanzadas do codificador e desmarque «Aplicar os límites de taxa de bits do servizo de emisión»." +Basic.Settings.Output.Simple.Warn.VideoBitrate="Advertencia: a taxa de bits de vídeo en transmisión estabelecerase en %1, que é o límite superior para o servizo de transmisión actual." +Basic.Settings.Output.Simple.Warn.AudioBitrate="Advertencia: a taxa de bits de son en transmisión estabelecerase en %1, que é o límite superior para o servizo de transmisión actual." Basic.Settings.Output.Simple.Warn.CannotPause="Aviso: Non é posíbel deter as gravacións se a calidade da gravación está estabelecida como «A mesma da emisión»." Basic.Settings.Output.Simple.Warn.Encoder="Aviso: a gravación cun codificador de software cunha calidade diferente á da emisión requirirá un uso de CPU adicional se se emite e grava ao mesmo tempo." Basic.Settings.Output.Simple.Warn.Lossless="Aviso: A calidade sen perda xera tamaños de ficheiro inmensamente grandes. A calidade sen perdas pode empregar á alza de 7 xigabytes de espazo de disco por minuto a altas resolucións e taxa de cadros. Non se recomenda «sen perdas» para gravacións longas a menos que dispoña dunha cantidade moi grande de espazo no disco." @@ -674,6 +687,11 @@ 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 preaxustado o uso de CPU baixo, aumenta o tamaño do ficheiro)" +Basic.Settings.Output.Simple.TwitchVodTrack="Pista VOD de Twitch (utiliza a pista 2)" +Basic.Settings.Output.Warn.EnforceResolutionFPS.Title="Resolución ou taxa de cadros por segundo incompatíbel" +Basic.Settings.Output.Warn.EnforceResolutionFPS.Msg="Este servizo de transmisión non admite a súa resolución de saída e/ou taxa de cadros por segundo actual. Cambiaranse aos valores compatíbeis máis próximos\n\n%1\n\nQuere continuar?" +Basic.Settings.Output.Warn.EnforceResolutionFPS.Resolution="Resolución: %1" +Basic.Settings.Output.Warn.EnforceResolutionFPS.FPS="Cadros por segundo: %1" Basic.Settings.Output.VideoBitrate="Taxa de bits de vídeo" Basic.Settings.Output.AudioBitrate="Taxa de bits de son" Basic.Settings.Output.Reconnect="Volver conectar automaticamente" @@ -688,15 +706,16 @@ Basic.Settings.Output.NoSpaceFileName="Xerar o nome do ficheiro sen espazos" Basic.Settings.Output.Adv.Rescale="Cambiar a escala da saída" Basic.Settings.Output.Adv.AudioTrack="Pista de son" Basic.Settings.Output.Adv.Streaming="Emisión" -Basic.Settings.Output.Adv.ApplyServiceSettings="Aplicar os axustes de codificador do servizo de emisión" Basic.Settings.Output.Adv.Audio.Track1="Pista 1" Basic.Settings.Output.Adv.Audio.Track2="Pista 2" Basic.Settings.Output.Adv.Audio.Track3="Pista 3" Basic.Settings.Output.Adv.Audio.Track4="Pista 4" Basic.Settings.Output.Adv.Audio.Track5="Pista 5" Basic.Settings.Output.Adv.Audio.Track6="Pista 6" +Basic.Settings.Output.Adv.TwitchVodTrack="Pista VOD do Twitch" Basic.Settings.Output.Adv.Recording="Gravando" +Basic.Settings.Output.Adv.Recording.RecType="Tipo de gravación" Basic.Settings.Output.Adv.Recording.Type="Tipo" Basic.Settings.Output.Adv.Recording.Type.Standard="Estándar" Basic.Settings.Output.Adv.Recording.Type.FFmpegOutput="Saída personalizada (FFmpeg)" @@ -749,7 +768,7 @@ Basic.Settings.Video.FPSFraction="Valor fraccionario de FPS" Basic.Settings.Video.Numerator="Numerador" Basic.Settings.Video.Denominator="Denominador" Basic.Settings.Video.Renderer="Xerador" -Basic.Settings.Video.InvalidResolution="Valor da resolución non válido. Debe ser [width] x [height] (por exemplo, 1920 x 1080)" +Basic.Settings.Video.InvalidResolution="Valor da resolución non válido. Debe ser [width] x [height] (p. ex.: 1920 x 1080)" Basic.Settings.Video.CurrentlyActive="A saída de vídeo está activa neste momento. Apaga calquera saída para cambiar a configuración de vídeo." Basic.Settings.Video.DisableAero="Desactivar Aero" @@ -824,13 +843,18 @@ Basic.AdvAudio="Propiedades de son avanzadas" Basic.AdvAudio.ActiveOnly="Só fontes activas" Basic.AdvAudio.Name="Nome" Basic.AdvAudio.Volume="Volume" +Basic.AdvAudio.VolumeSource="Volume para «%1»" Basic.AdvAudio.Mono="Mono" +Basic.AdvAudio.MonoSource="Mestura monoaural para «%1»" Basic.AdvAudio.Balance="Balance" +Basic.AdvAudio.BalanceSource="Balance para «%1»" Basic.AdvAudio.SyncOffset="Desprazamento da sincronización" +Basic.AdvAudio.SyncOffsetSource="Desprazamento do sincronismo para «%1»" Basic.AdvAudio.Monitoring="Monitorización do son" Basic.AdvAudio.Monitoring.None="Monitor apagado" Basic.AdvAudio.Monitoring.MonitorOnly="Só o monitor (silenciar a saída)" Basic.AdvAudio.Monitoring.Both="Monitor e saída" +Basic.AdvAudio.MonitoringSource="Monitorización de son para «%1»" Basic.AdvAudio.AudioTracks="Pistas" Basic.Settings.Hotkeys="Teclas rápidas" @@ -890,7 +914,7 @@ SceneItemShow="Amosar «%1»" SceneItemHide="Agochar «%1»" OutputWarnings.NoTracksSelected="Debe seleccionar, cando menos, unha pista" -OutputWarnings.MP4Recording="Aviso: as gravacións gardadas en MP4/MOV non serán recuperábeis se non se pode rematar o ficheiro (por exemplo, como resultado de BSOD, perdas de enerxía, etc.). Se quere gravar varias pistas de son, considere empregar MKV e converter a gravación a MP4/MOV unha vez rematada (Ficheiro → Gravacións de conversións)" +OutputWarnings.MP4Recording="Advertencia: as gravacións gardadas en MP4/MOV non serán recuperábeis se non se pode rematar o ficheiro (por exemplo, como resultado de BSOD, perdas de enerxía, etc.). Se quere gravar varias pistas de son, considere empregar MKV e converter a gravación a MP4/MOV unha vez rematada (Ficheiro → Gravacións de conversións)" OutputWarnings.CannotPause="Aviso: Non é posíbel deter as gravacións se está estabelecido o codificador da gravación «(Utilizar o codificador da emisión)»" FinalScene.Title="Eliminar escena" diff --git a/UI/data/locale/he-IL.ini b/UI/data/locale/he-IL.ini index c991d0e..160c056 100644 --- a/UI/data/locale/he-IL.ini +++ b/UI/data/locale/he-IL.ini @@ -93,12 +93,14 @@ LockVolume="נעילת שמע" LogViewer="מציג היומן" ShowOnStartup="הצג בעת הפעלה" OpenFile="פתיחת קובץ" +AddValue="הוספת %1" AlreadyRunning.Title="OBS פועל כבר" AlreadyRunning.Text="OBS פועל כבר! אלא אם התכוונת לעשות את זה, אנא סגור כל מופע קיים לפני נסיון להפעיל מופע חדש. אנא בדוק אם קיים מופע הגדר ממוזער במגש המערכת." AlreadyRunning.LaunchAnyway="הפעל בכל מקרה" ChromeOS.Title="פלטפורמה לא נתמכת" +ChromeOS.Text="נראה שOBS הופעל בתוך מכל של ChromeOS. פלטפורמה זו אינה נתמכת" DockCloseWarning.Title="סגירת חלון ניתן להצמדה" DockCloseWarning.Text="סגרת עכשיו חלון הניתן להצמדה. אם ברצונך להציג אותו שוב, השתמש בתפריט תצוגה -> הצמדות בשורת התפריט." @@ -145,6 +147,7 @@ Basic.AutoConfig.StartPage.PrioritizeStreaming="מיטוב עבור הזרמה, Basic.AutoConfig.StartPage.PrioritizeRecording="מיטוב רק עבור הקלטה, לא תהיה הזרמה" Basic.AutoConfig.StartPage.PrioritizeVirtualCam="אני אשתמש רק במצלמה הווירטואלית" Basic.AutoConfig.VideoPage="הגדרות וידאו" +Basic.AutoConfig.VideoPage.SubTitle="ציין בספציפיות את הגדרות הווידאו המבוקשות עבורך" Basic.AutoConfig.VideoPage.BaseResolution.UseCurrent="השתמש בנוכחי (%1x%2)" Basic.AutoConfig.VideoPage.BaseResolution.Display="תצוגה %1 (%2x%3)" Basic.AutoConfig.VideoPage.FPS.UseCurrent="השתמש בנוכחי (%1)" @@ -158,6 +161,7 @@ Basic.AutoConfig.StreamPage.DisconnectAccount="נתק את חשבון" Basic.AutoConfig.StreamPage.DisconnectAccount.Confirm.Title="לנתק את חשבון?" Basic.AutoConfig.StreamPage.DisconnectAccount.Confirm.Text="שינוי זה יחול באופן מיידי. האם אתה בטוח שברצונך לנתק את החשבון שלך?" Basic.AutoConfig.StreamPage.GetStreamKey="קבלת מפתח הזרמת נתונים" +Basic.AutoConfig.StreamPage.MoreInfo="מידע נוסף" Basic.AutoConfig.StreamPage.UseStreamKey="השתמש במפתח הזרמת נתונים" Basic.AutoConfig.StreamPage.Service="שירות" Basic.AutoConfig.StreamPage.Service.ShowAll="הצג הכל..." @@ -186,6 +190,8 @@ Basic.AutoConfig.TestPage.Result.StreamingEncoder="מקודד זרימה" Basic.AutoConfig.TestPage.Result.RecordingEncoder="מקודד הקלטה" Basic.AutoConfig.TestPage.Result.Header="התוכנית קבעה כי אלה ההגדרות המיטביות עבורך:" Basic.AutoConfig.TestPage.Result.Footer="כדי להשתמש בהגדרות אלה, לחץ על החל הגדרות. כדי להגדיר מחדש את האשף ולנסות שוב, לחץ על אחורה. להגדיר ידנית את הגדרות, לחץ על ביטול ולאחר מכן פתח את הגדרות." +Basic.AutoConfig.Info="אשף ההגדרה האוטומטית ימצא את ההגדרות הטובות ביותר בהתבסס על מפרט המחשב ומהירות האינטרנט שלך." +Basic.AutoConfig.RunAnytime="זה יכול לרוץ בכל זמן על ידי כניסה לתפריט הכלים." Basic.Stats="סטטיסטיקות" Basic.Stats.CPUUsage="שימוש במעבד" @@ -360,8 +366,6 @@ Deinterlacing.Yadif2x="Yadif 2x" Deinterlacing.TopFieldFirst="שדה עליון ראשון" Deinterlacing.BottomFieldFirst="שדה תחתון ראשון" -VolControl.SliderUnmuted="מחוון העוצמה עבור '%1': %2" -VolControl.SliderMuted="מחוון העוצמה עבור '%1': %2 (כרגע מושתק)" VolControl.Mute="השתק '%1'" VolControl.Properties="מאפיינים עבור '%1'" @@ -377,6 +381,7 @@ Basic.Main.RenameSceneCollection.Title="שינוי שם של אוסף הסצינ AddProfile.Title="הוסף פרופיל" AddProfile.Text="אנא הזן את שם הפרופיל" +AddProfile.WizardCheckbox="הראה את אשף ההגדרה האוטומית" RenameProfile.Title="שנה שם פרופיל" @@ -391,6 +396,7 @@ Basic.SourceSelect.CreateNew="צור חדש" Basic.SourceSelect.AddExisting="הוסף קיימים" Basic.SourceSelect.AddVisible="הפוך מקור לגלוי" + Basic.PropertiesWindow="מאפיינים עבור \"%1\"" Basic.PropertiesWindow.AutoSelectFormat="%1 (בחירה אוטומטית: %2)" Basic.PropertiesWindow.SelectColor="בחר צבע" @@ -477,6 +483,8 @@ Basic.Main.StoppingReplayBuffer="עצירת מאגר החוזר..." Basic.Main.StopStreaming="עצור זרם נתונים" Basic.Main.StoppingStreaming="עוצר זרם נתונים..." Basic.Main.ForceStopStreaming="עצור זרם נתונים (בטל השהייה)" +Basic.Main.ShowContextBar="הראה את לוח הכלים של המקורות" +Basic.Main.HideContextBar="החבא את לוח הכלים של המקורות" Basic.Main.StopVirtualCam="עצור מצלמה וירטואלית" Basic.Main.Group="קבוצה %1" Basic.Main.GroupItems="קבץ פריטים נבחרים" @@ -533,6 +541,8 @@ Basic.MainMenu.View.Docks="עגינה" Basic.MainMenu.View.Docks.ResetUI="איפוס UI" Basic.MainMenu.View.Docks.LockUI="נעילת UI" Basic.MainMenu.View.Docks.CustomBrowserDocks="חלונות הצמדה מותאמים אישית של דפדפן..." +Basic.MainMenu.View.ListboxToolbars="כפתורי רישמת המקורות\סצנות" +Basic.MainMenu.View.ContextBar="לוח הכלים של המקורות" Basic.MainMenu.View.SceneTransitions="מעברי סצינות (&C)" Basic.MainMenu.View.SourceIcons="אייקוני מקור" Basic.MainMenu.View.StatusBar="שורת מצב (&S)" @@ -626,13 +636,19 @@ Basic.Settings.Stream.StreamSettingsWarning="פתיחת הגדרות" Basic.Settings.Stream.MissingUrlAndApiKey="שרת ומפתח הזרמת נתונים חסרים\n\nגש לתפריט ההגדרות בכדי להכניס שרת ומפתח הזרמת נתונים בלשונית 'זרם נתונים'." Basic.Settings.Stream.MissingUrl="מפתח הזרמת נתונים חסר\n\nגש לתפריט ההגדרות בכדי להכניס מפתח הזרמת נתונים בלשונית 'זרם נתונים'." Basic.Settings.Stream.MissingStreamKey="מפתח הזרמת נתונים חסר\n\nגש לתפריט ההגדרות בכדי להכניס מפתח הזרמה בלשונית 'הזרמת נתונים'." +Basic.Settings.Stream.IgnoreRecommended="התעלם מהמלצות להגדרות של שירות ההזרמה" +Basic.Settings.Stream.IgnoreRecommended.Warn.Title="עקיפת ההגדרות המומלצות" +Basic.Settings.Stream.IgnoreRecommended.Warn.Text="אזהרה: התעלמות מגבולות השירות יכולה לגרום לאיכות הזרמה ירודה או אפילו למנוע הזרמה. להמשיך?" +Basic.Settings.Stream.Recommended.MaxVideoBitrate="קצב סיביות וידאו מקסימלי: %1 קילובייט לשנייה" +Basic.Settings.Stream.Recommended.MaxAudioBitrate="קצב סיביות אודיו מקסימלי: %1 קילובייט לשנייה" +Basic.Settings.Stream.Recommended.MaxResolution="רזולוציה מקסימלית: %1" +Basic.Settings.Stream.Recommended.MaxFPS="קצב פריימים לשנייה מקסימלי: %1" 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.DynamicBitrate="התאם דינאמית את קצב הביטים בהתאם לעומס על הרשת" Basic.Settings.Output.DynamicBitrate.Beta="התאם דינאמית את קצב הביטים בהתאם לעומס על הרשת (בטא)" Basic.Settings.Output.DynamicBitrate.TT="במקום שפריימים יפלו כתוצאה מעומס על הרשת, קצב הביטים ישתנה באופן דינאמי.\n\nיש לשים לב כי הגדרה זו עלולה להעלות את ההשהייה לצופים בעת עומס פתאומי על הרשת.\nכאשר קצב הביטים יורד, עשויות לעבור כמה דקות עד שישוחזר.\n\nכרגע נתמך רק עבור RTMP." @@ -653,8 +669,8 @@ 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.VideoBitrate="אזהרה, קצב הסיביות של הזרמת הוווידאו יוגדר ל%1, שהוא הגבול הכי גבוה לשירות ההזרמה הנוכחי." +Basic.Settings.Output.Simple.Warn.AudioBitrate="אזהרה, קצב הסיביות של הזרמת האודיו יוגדר ל%1, שהוא הגבול הכי גבוה לשירות ההזרמה הנוכחי." Basic.Settings.Output.Simple.Warn.CannotPause="אזהרה: לא ניתן להשהות הקלטות אם מקודד ההקלטה מוגדר על \"השתמש במקודד זרם נתונים\"." Basic.Settings.Output.Simple.Warn.Encoder="אזהרה: הקלטה עם מקודד תוכנה באיכות שונה מאשר זרם הנתונים ידרוש שימוש במשאבי מעבד נוספים אם מתבצעת הקלטה וזרם נתונים במקביל." Basic.Settings.Output.Simple.Warn.Lossless="אזהרה: איכות ללא אובדן יוצר גדלי קבצים גדולים מאוד! איכות ללא אובדן נתונים יכול להשתמש ביותר מ-7 ג'יגה-בתים של שטח דיסק לדקה ברזולוציות גבוהות ופריימים. שימוש באיכות ללא אובדן אינו מומלץ להקלטות ארוכות אלא אם קיים שטח דיסק פנוי גדול מאד." @@ -665,6 +681,11 @@ 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="תוכנה (x 264 השימוש בהגדרת מעבד נמוך, גודל הקובץ גדל)" +Basic.Settings.Output.Simple.TwitchVodTrack="החלף פס VOD (שימוש בפס מספר 2)" +Basic.Settings.Output.Warn.EnforceResolutionFPS.Title="קצב פריימים\רזולוציה לא נתמכת" +Basic.Settings.Output.Warn.EnforceResolutionFPS.Msg="שירות הזרמה זה לא תומך ברזולציה ובקצב הפריימים הנוכחים שהגדרת. הם ישתנו לערך הכי קרוב ונתמך: \n\n%1\n\n האם תרצי\ה להמשיך?" +Basic.Settings.Output.Warn.EnforceResolutionFPS.Resolution="רזולוציה: %1" +Basic.Settings.Output.Warn.EnforceResolutionFPS.FPS="פריימים לשנייה: %1" Basic.Settings.Output.VideoBitrate="קצב סיביות וידאו" Basic.Settings.Output.AudioBitrate="קצב סיביות שמע" Basic.Settings.Output.Reconnect="חיבור מחדש באופן אוטומטי" @@ -679,13 +700,13 @@ 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.Audio.Track5="רצועה 5" Basic.Settings.Output.Adv.Audio.Track6="רצועה 6" +Basic.Settings.Output.Adv.TwitchVodTrack="פס VOD של טוויץ'" Basic.Settings.Output.Adv.Recording="הקלטה" Basic.Settings.Output.Adv.Recording.Type="סוג" @@ -761,6 +782,7 @@ Basic.Settings.Audio.PeakMeterType="סוג שיא המד" Basic.Settings.Audio.PeakMeterType.SamplePeak="שיא דגימה" Basic.Settings.Audio.PeakMeterType.TruePeak="שיא אמיתי (שימוש גבוה יותר ב-CPU)" Basic.Settings.Audio.MultiChannelWarning.Enabled="אזהרה: שמע צליל היקפי מאופשר." +Basic.Settings.Audio.MultichannelWarning="עבור הזרמה, יש לבדוק האם שירות ההזרמה שלך תומך בקבלת והשמעת צליל סראונד. דוגמאות לשירותים התומכים בסאונד סראונד באופן מלא: Facebook 360 Live, Mixer RTMP, Smashcast. למרות ש-Facebook Live ו-YouTube Live שניהם תומכים בקבלת סראונד, שירות Facebook Live מבצע הפחתת ערבול לסטריאו, בעוד YouTube Live מנגן רק שני ערוצים.\n\nערוצי האודיו של OBS מותאמים לסאונד סראונד, אך תמיכה בתוספי VST אינה מובטחת." Basic.Settings.Audio.MultichannelWarning.Title="האם להפעיל שמע צליל היקפי?" Basic.Settings.Audio.MultichannelWarning.Confirm="אתה בטוח שאתה רוצה לאפשר קול שמע מקיף?" Basic.Settings.Audio.Devices="התקני קול גלובליים" @@ -928,11 +950,15 @@ Restart="אתחל" NeedsRestart="OBS Studio צריך לאתחל. ברצונך לאתחל עכשיו?" ContextBar.NoSelectedSource="לא נבחר מקור" +ContextBar.ResetTransform="אפס שינויים" ContextBar.FitToCanvas="התאם לקנבס" ContextBar.MediaControls.PlayMedia="ניגון מדיה" ContextBar.MediaControls.PauseMedia="השהה מדיה" ContextBar.MediaControls.StopMedia="עצור מדיה" +ContextBar.MediaControls.RestartMedia="התחל מדיה מחדש" ContextBar.MediaControls.PlaylistNext="הבא בפלייליסט" ContextBar.MediaControls.PlaylistPrevious="הקודם בפלייליסט" +ContextBar.MediaControls.MediaProperties="מאפייני מדיה" +ContextBar.MediaControls.BlindSeek="ווידג'ט חיפוש מדיה" diff --git a/UI/data/locale/hi-IN.ini b/UI/data/locale/hi-IN.ini index 3152c3d..32ba29e 100644 --- a/UI/data/locale/hi-IN.ini +++ b/UI/data/locale/hi-IN.ini @@ -172,6 +172,7 @@ QuickTransitions.HotkeyName="त्वरित संक्रांति: %1" + Basic.Main.PauseRecording="रिकॉर्डिंग रोकें" diff --git a/UI/data/locale/hr-HR.ini b/UI/data/locale/hr-HR.ini index 56b1765..4d0173b 100644 --- a/UI/data/locale/hr-HR.ini +++ b/UI/data/locale/hr-HR.ini @@ -91,6 +91,7 @@ LockVolume="Zakoči glasnoću" LogViewer="Prikaz zapisnika" ShowOnStartup="Prikaži na startu" OpenFile="Otvori datoteku" +AddValue="Dodaj %1" AlreadyRunning.Title="OBS je već pokrenut" AlreadyRunning.Text="OBS je već pokrenut! Osim ako si mislio da biste to učinili, isključite sve postojeće pojave OBS prije nego što pokušate pokrenuti novu instancu. Ako imate OBS postavljen na smanjivanje u traku sustava, provjerite ako to još uvijek radi tamo." @@ -311,6 +312,7 @@ Basic.SourceSelect.CreateNew="Napravi novi" Basic.SourceSelect.AddExisting="Dodaj postojeći" Basic.SourceSelect.AddVisible="Prikaži izvor" + Basic.PropertiesWindow="Svojstva za '%1'" Basic.PropertiesWindow.AutoSelectFormat="%1 (automatski odabir: %2)" Basic.PropertiesWindow.SelectColor="Odaberi boju" @@ -494,7 +496,6 @@ Basic.Settings.Output.Format="Format snimanja" Basic.Settings.Output.Encoder="Enkoder" Basic.Settings.Output.SelectDirectory="Odaberi direktorijum za snimanje" Basic.Settings.Output.SelectFile="Odaberi datoteku za snimanje" -Basic.Settings.Output.EnforceBitrate="Sprovedi ograničenja u protoku striming servisa" Basic.Settings.Output.Mode="Režim izlaza" Basic.Settings.Output.Mode.Simple="Jednostavno" Basic.Settings.Output.Mode.Adv="Napredno" @@ -505,8 +506,6 @@ Basic.Settings.Output.Simple.RecordingQuality.Stream="Isto kao strim" Basic.Settings.Output.Simple.RecordingQuality.Small="Visoki kvalitet, osrednja veličina datoteke" Basic.Settings.Output.Simple.RecordingQuality.HQ="Kvalitet sa neprimetnim razlikama, velika datoteka" Basic.Settings.Output.Simple.RecordingQuality.Lossless="Kvalitet bez gubitka, izričito velika datoteka" -Basic.Settings.Output.Simple.Warn.VideoBitrate="Upozorenje: Video protok strima će biti postavljen na %1, što je gornja granica za trenutni striming servis. Ako ste sigurni da želite ići preko %1, omogućite napredne opcije enkodera i isključite \"Sprovedi ograničenja u protoku striming servisa\"." -Basic.Settings.Output.Simple.Warn.AudioBitrate="Upozorenje: Zvučni protok strima će biti postavljen na %1, što je gornja granica za trenutni striming servis. Ako ste sigurni da želite ići preko %1, omogućite napredne opcije enkodera i isključite \"Sprovedi ograničenja u protoku striming servisa\"." Basic.Settings.Output.Simple.Warn.Encoder="Upozorenje: Snimanje sa softverskim enkoderom drugačijeg kvaliteta u odnosu na strim će zahtevati dodatnu procesorsku snagu ako strimujete i snimate u isto vreme." Basic.Settings.Output.Simple.Warn.Lossless="Upozorenje: Kvalitet bez gubitka stvara izričito velike datoteke! Kvalitet bez gubitka može koristiti više od 7 gigabajta prostora na disku po minutu pri visokim rezolucijama i framerate-om. Kvalitet bez gubitka nije preporučen za duže snimanje osim ako imate veliku količinu slobodnog prostora na disku." Basic.Settings.Output.Simple.Warn.Lossless.Msg="Da li ste sigurni da želite koristiti kvalitet bez gubitka?" @@ -528,7 +527,6 @@ Basic.Settings.Output.NoSpaceFileName="Stvori ime datoteke bez razmaka" Basic.Settings.Output.Adv.Rescale="Skaliraj izlaz" Basic.Settings.Output.Adv.AudioTrack="Zvučni izvor" Basic.Settings.Output.Adv.Streaming="Strimovanje" -Basic.Settings.Output.Adv.ApplyServiceSettings="Prisilna podešavanja enkodera striming servisa" Basic.Settings.Output.Adv.Audio.Track1="Izvor 1" Basic.Settings.Output.Adv.Audio.Track2="Izvor 2" Basic.Settings.Output.Adv.Audio.Track3="Izvor 3" diff --git a/UI/data/locale/hu-HU.ini b/UI/data/locale/hu-HU.ini index e11badc..aef3bda 100644 --- a/UI/data/locale/hu-HU.ini +++ b/UI/data/locale/hu-HU.ini @@ -28,10 +28,10 @@ Mono="Mono" Stereo="Sztereó" DroppedFrames="Eldobott képkockák: %1 (%2%)" StudioProgramProjector="Teljes képernyős projektor (program)" -PreviewProjector="Teljes képernyős projektor (előnézet)" -SceneProjector="Teljes képernyős projektor (jelenet)" -SourceProjector="Teljes képernyős projektor (forrás)" -StudioProgramWindow="Ablakos projektor (program)" +PreviewProjector="Teljes képernyős projektor (Előnézet)" +SceneProjector="Teljes képernyős projektor (Jelenet)" +SourceProjector="Teljes képernyős projektor (Forrás)" +StudioProgramWindow="Ablakos projektor (Program)" PreviewWindow="Ablakos projektor (Előnézet)" SceneWindow="Ablakos projektor (Jelenet)" SourceWindow="Ablakos projektor (Forrás)" @@ -90,7 +90,7 @@ Percent="Százalék" RefreshBrowser="Frissítés" AspectRatio="Képarány %1:%2" LockVolume="Hangerő zárolása" -LogViewer="Log Megjelenítő" +LogViewer="Napló megjelenítő" ShowOnStartup="Mutatás indításkor" OpenFile="Fájl megnyitása" AddValue="%1 hozzáadása" @@ -161,6 +161,7 @@ Basic.AutoConfig.StreamPage.DisconnectAccount="Felhasználó szétkapcsolása" Basic.AutoConfig.StreamPage.DisconnectAccount.Confirm.Title="Felhasználó szétkapcsolása?" Basic.AutoConfig.StreamPage.DisconnectAccount.Confirm.Text="Ez a változtatás azonnal érvénybe lép. Biztosan megszakítja a kapcsolatot a fiókjával?" Basic.AutoConfig.StreamPage.GetStreamKey="Stream Kulcs lekérése" +Basic.AutoConfig.StreamPage.MoreInfo="További információk" Basic.AutoConfig.StreamPage.UseStreamKey="Stream kulcs használata" Basic.AutoConfig.StreamPage.Service="Szolgáltatás" Basic.AutoConfig.StreamPage.Service.ShowAll="Összes megjelenítése…" @@ -365,8 +366,8 @@ Deinterlacing.Yadif2x="Yadif 2x" Deinterlacing.TopFieldFirst="Felső mező először" Deinterlacing.BottomFieldFirst="Alsó mező először" -VolControl.SliderUnmuted="Hangerő csúszka a '%1'-hez: %2" -VolControl.SliderMuted="Hangerő csúszka '%1'-hez: %2 (jelenleg némítva)" +VolControl.SliderUnmuted="'%1' hangerő csúszkája:" +VolControl.SliderMuted="'%1' hangerő csúszkája: (jelenleg némítva)" VolControl.Mute="Némítás '%1'" VolControl.Properties="Tulajdonságok a '%1'-hez" @@ -382,6 +383,7 @@ Basic.Main.RenameSceneCollection.Title="Jelenet gyűjtemény átnevezése" AddProfile.Title="Profil hozzáadása" AddProfile.Text="Kérjük, adja meg a profil nevét" +AddProfile.WizardCheckbox="Automatikus beállításvarázsló megjelenítése" RenameProfile.Title="Profil átnevezése" @@ -396,6 +398,11 @@ Basic.SourceSelect.CreateNew="Új létrehozása" Basic.SourceSelect.AddExisting="Létező tartalom hozzáadása" Basic.SourceSelect.AddVisible="Forrás láthatóvá tétele" +Basic.Main.Sources.Visibility="Láthatóság" +Basic.Main.Sources.VisibilityDescription="Beállítja '%1' láthatóságát a vásznon" +Basic.Main.Sources.Lock="Zárolás" +Basic.Main.Sources.LockDescription="Zárolja '%1' pozícióját és méretét a vásznon" + Basic.PropertiesWindow="Tulajdonságok: '%1'" Basic.PropertiesWindow.AutoSelectFormat="%1 (autokiválasztás: %2)" Basic.PropertiesWindow.SelectColor="Szín kiválasztása" @@ -635,13 +642,19 @@ Basic.Settings.Stream.StreamSettingsWarning="Beállítások megnyitása" Basic.Settings.Stream.MissingUrlAndApiKey="Hiányzó elérési út és stream kulcs.\n\nNyissa meg a beállításokat, hogy megadja az elérési utat és a stream kulcsot a 'stream' fülön." Basic.Settings.Stream.MissingUrl="Hiányzó elérési út.\n\nNyissa meg a beállításokat, hogy megadja az elérési utat a 'stream' fülön." Basic.Settings.Stream.MissingStreamKey="Hiányzó stream kulcs.\n\nNyissa meg a beállításokat, hogy megadja a stream kulcsot a 'stream' fülön." +Basic.Settings.Stream.IgnoreRecommended="Streamkiszolgáló ajánlott beállításainak figyelmen kívül hagyása" +Basic.Settings.Stream.IgnoreRecommended.Warn.Title="Ajánlott Beállítások Felülbírálása" +Basic.Settings.Stream.IgnoreRecommended.Warn.Text="Figyelem: A kiszolgáló limitációinak figyelmen kívül hagyása gyengébb minőséget eredményezhet vagy megakadályozhatja az adást.\n\nFolytatja?" +Basic.Settings.Stream.Recommended.MaxVideoBitrate="Maximum Video Bitráta: %1 kbps" +Basic.Settings.Stream.Recommended.MaxAudioBitrate="Maximum Audio Bitráta: %1 kbps" +Basic.Settings.Stream.Recommended.MaxResolution="Maximális Felbontás: %1" +Basic.Settings.Stream.Recommended.MaxFPS="Maximális FPS: %1" Basic.Settings.Output="Kimenet" Basic.Settings.Output.Format="Felvétel formátuma" Basic.Settings.Output.Encoder="Kódoló" Basic.Settings.Output.SelectDirectory="Felvételi könyvtár kiválasztása" Basic.Settings.Output.SelectFile="Felvétel fájljának kiválasztása" -Basic.Settings.Output.EnforceBitrate="Stream kiszolgáló bitsebesség korlátainak kényszerítése" Basic.Settings.Output.DynamicBitrate="Dinamikus bitráta változtatás a hálózati terheléssel való megbirkózás érdekében" Basic.Settings.Output.DynamicBitrate.Beta="Dinamikus bitráta változtatás a hálózati terheléssel való megbirkózás érdekében (Béta)" Basic.Settings.Output.DynamicBitrate.TT="Hálózati terhelés esetén a képkockák eldobása helyett, dinamikusan változik a bitráta menet közben.\n\nTartsa észben, hogy ez növelheti a késleltetést ön és a nézők között, hogyha hirtelen megnövekszik a terhelés.\nAmikor a bitráta lezuhan, akár percekig is eltarthat, amíg helyreáll.\n\nAktuálisan csak RTMP használata esetén támogatott." @@ -662,8 +675,8 @@ Basic.Settings.Output.Simple.RecordingQuality.Stream="Ugyanaz, mint a stream" Basic.Settings.Output.Simple.RecordingQuality.Small="Jó minőség, közepes fájlméret" Basic.Settings.Output.Simple.RecordingQuality.HQ="Megkülönböztethetetlen minőség, nagy fájlméret" Basic.Settings.Output.Simple.RecordingQuality.Lossless="Veszteségmentes minőség, hatalmas fájlméret" -Basic.Settings.Output.Simple.Warn.VideoBitrate="Figyelem: Az adás videó bitsebessége %1 értéken áll, ami a kiválasztott kiszolgáló felső határértéke. Amennyiben túl kívánja lépni a megadott %1 értéket, úgy engedélyezze a haladó kódolási opciókat és törölje a \"stream kiszolgáló bitsebesség korlátainak kényszerítése\" opciót." -Basic.Settings.Output.Simple.Warn.AudioBitrate="Figyelem: Az adás audio bitsebessége %1 értéken áll, ami a kiválasztott kiszolgáló felső határértéke. Amennyiben túl kívánja lépni a megadott %1 értéket, úgy engedélyezze a haladó kódolási opciókat és törölje a \"stream kiszolgáló bitsebesség korlátainak kényszerítése\" opciót." +Basic.Settings.Output.Simple.Warn.VideoBitrate="Figyelem: A stream-elés video bitrátája be lesz állítva a következőre: %1, mivel ennyi a kiválasztott streaming szolgáltatás felső határa." +Basic.Settings.Output.Simple.Warn.AudioBitrate="Figyelem: A stream-elés audio bitrátája be lesz állítva a következőre: %1, mivel ennyi a kiválasztott streaming szolgáltatás felső határa." Basic.Settings.Output.Simple.Warn.CannotPause="Figyelmeztetés: A felvételeket nem lehet szüneteltetni, ha a felvétel minősége \"Ugyanaz mint a stream\"-re van állítva." Basic.Settings.Output.Simple.Warn.Encoder="Figyelem: A streamtől eltérő minőséggel történő rögzítés, további CPU erőforrásokat igényel, ha egyidejűleg használja mindkettőt." Basic.Settings.Output.Simple.Warn.Lossless="Figyelem: A veszteségmentes minőséggel történő felvétel hatalmas fájlméretet generál. Ezzel a minőséggel percenként akár 7 gigabájt adatot is generálhat nagy felbontáson és képkockasebességen. Ez az eljárás nem ajánlott hosszú felvételekhez, kivéve ha hatalmas lemezterület áll rendelkezésre." @@ -674,6 +687,8 @@ 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.Warn.EnforceResolutionFPS.Resolution="Felbontás: %1" +Basic.Settings.Output.Warn.EnforceResolutionFPS.FPS="FPS: %1" Basic.Settings.Output.VideoBitrate="Videó bitsebesség" Basic.Settings.Output.AudioBitrate="Audio bitsebesség" Basic.Settings.Output.Reconnect="Automatikus újracsatlakozás" @@ -688,15 +703,16 @@ Basic.Settings.Output.NoSpaceFileName="Fájlnév generálása helyfoglalás nél Basic.Settings.Output.Adv.Rescale="Kimenet átméretezése" Basic.Settings.Output.Adv.AudioTrack="Hangsáv" Basic.Settings.Output.Adv.Streaming="Streamelés" -Basic.Settings.Output.Adv.ApplyServiceSettings="A kiszolgáló kódoló beállításainak kényszerítése" Basic.Settings.Output.Adv.Audio.Track1="Sáv 1" Basic.Settings.Output.Adv.Audio.Track2="Sáv 2" Basic.Settings.Output.Adv.Audio.Track3="Sáv 3" Basic.Settings.Output.Adv.Audio.Track4="Sáv 4" Basic.Settings.Output.Adv.Audio.Track5="Sáv 5" Basic.Settings.Output.Adv.Audio.Track6="Sáv 6" +Basic.Settings.Output.Adv.TwitchVodTrack="Twitch VOD Track" Basic.Settings.Output.Adv.Recording="Rögzítés" +Basic.Settings.Output.Adv.Recording.RecType="Felvétel típusa" Basic.Settings.Output.Adv.Recording.Type="Típus" Basic.Settings.Output.Adv.Recording.Type.Standard="Szabvány" Basic.Settings.Output.Adv.Recording.Type.FFmpegOutput="Egyéni kimenet (FFmpeg)" @@ -824,6 +840,7 @@ Basic.AdvAudio="Speciális hangtulajdonságok" Basic.AdvAudio.ActiveOnly="Csak Aktív Források" Basic.AdvAudio.Name="Név" Basic.AdvAudio.Volume="Hangerő" +Basic.AdvAudio.VolumeSource="'%1' hangereje" Basic.AdvAudio.Mono="Mono" Basic.AdvAudio.Balance="Egyensúly" Basic.AdvAudio.SyncOffset="Szinkron eltolás" diff --git a/UI/data/locale/id-ID.ini b/UI/data/locale/id-ID.ini index 78289dd..f0cbe41 100644 --- a/UI/data/locale/id-ID.ini +++ b/UI/data/locale/id-ID.ini @@ -7,36 +7,36 @@ Cancel="Batal" Close="Tutup" Save="Simpan" Discard="Buang" -Disable="Nonaktifkan" +Disable="Nonaktif" Yes="Ya" No="Tidak" -Add="Tambah" +Add="Tambahkan" Remove="Hapus" Rename="Ubah Nama" Interact="Interaksi" Filters="Filter" Properties="Properti" -MoveUp="Ke Atas" -MoveDown="Ke Bawah" +MoveUp="Pindah Ke Atas" +MoveDown="Pindah Ke Bawah" Settings="Pengaturan" -Display="Tampilan" +Display="Layar" Name="Nama" Exit="Keluar" Mixer="Mixer Audio" Browse="Telusuri" Mono="Mono" Stereo="Stereo" -DroppedFrames="Frame drop %1 (%2%)" +DroppedFrames="Frame Ter-drop %1 (%2%)" StudioProgramProjector="Proyektor Layar Penuh (Program)" PreviewProjector="Proyektor Layar Penuh (Pratinjau)" SceneProjector="Proyektor Layar Penuh (Adegan)" SourceProjector="Proyektor Layar Penuh (Sumber)" -StudioProgramWindow="Proyektor Windowed (Program)" -PreviewWindow="Proyektor Windowed (Pratinjau)" -SceneWindow="Proyektor Windowed (Adegan)" -SourceWindow="Proyektor Windowed (Sumber)" -MultiviewProjector="Multiview (Layar Penuh)" -MultiviewWindowed="Multiview (Windowed)" +StudioProgramWindow="Proyektor Berjendela (Program)" +PreviewWindow="Proyektor Berjendela (Pratinjau)" +SceneWindow="Proyektor Berjendela (Adegan)" +SourceWindow="Proyektor Berjendela (Sumber)" +MultiviewProjector="Tampilan Multi (Layar Penuh)" +MultiviewWindowed="Tampilan Multi (Berjendela)" ResizeProjectorWindowToContent="Sesuaikan jendela dengan konten" Clear="Bersihkan" Revert="Pulihkan" @@ -48,8 +48,8 @@ New="Baru" Duplicate="Duplikat" Enable="Aktifkan" DisableOSXVSync="Nonaktifkan macOS V-Sync" -ResetOSXVSyncOnExit="Reset macOS V-Sync saat Keluar" -HighResourceUsage="Pengkodean kelebihan beban! Pertimbangkan untuk mengecilkan pengaturan video atau memakai preset pengkodean yang lebih cepat." +ResetOSXVSyncOnExit="Setel Ulang macOS V-Sync saat Keluar" +HighResourceUsage="Pengkodean kelebihan beban! Pertimbangkan untuk menurunkan pengaturan video atau gunakan preset pengkodean yang lebih cepat." Transition="Transisi" QuickTransitions="Transisi Cepat" FadeToBlack="Pudar jadi Hitam" @@ -57,7 +57,7 @@ Left="Kiri" Right="Kanan" Top="Atas" Bottom="Bawah" -Reset="Reset" +Reset="Atur Ulang" Hours="Jam" Minutes="Menit" Seconds="Detik" @@ -68,69 +68,70 @@ Export="Ekspor" Copy="Salin" Paste="Tempel" PasteReference="Tempel (Referensi)" -PasteDuplicate="Rekatkan (Duplikat)" +PasteDuplicate="Tempel (Duplikat)" RemuxRecordings="Remux Rekaman" -Next="Selanjutnya" +Next="Berikutnya" Back="Kembali" -Defaults="Default" +Defaults="Bawaan" HideMixer="Sembunyikan di Mixer" -TransitionOverride="Paksa Transisi" +TransitionOverride="Menimpa Transisi" None="Tidak ada" -StudioMode.Preview="Preview" +StudioMode.Preview="Pratinjau" StudioMode.Program="Program" -ShowInMultiview="Tampilkan di Multiview" +ShowInMultiview="Tampilkan di Tampilan Multi" VerticalLayout="Tata Letak Vertikal" -Group="Kelompok" +Group="Grup" DoNotShowAgain="Jangan tampilkan lagi" -Default="(Default)" +Default="(Bawaan)" Calculating="Menghitung..." Fullscreen="Layar Penuh" -Windowed="Windowed" +Windowed="Berjendela" Percent="Persen" -RefreshBrowser="Refresh" +RefreshBrowser="Muat Ulang" AspectRatio="Rasio Aspek %1:%2" LockVolume="Kunci Volume" -LogViewer="Penampil Log" +LogViewer="Penampil Catatan" ShowOnStartup="Tampilkan saat memulai" -OpenFile="Buka file" +OpenFile="Buka berkas" +AddValue="Tambah %1" AlreadyRunning.Title="OBS sudah berjalan" -AlreadyRunning.Text="OBS sudah berjalan! Kecuali Anda bermaksud melakukan ini, harap matikan semua jendela OBS yang ada sebelum mencoba menjalankan jendela baru. Jika Anda memiliki OBS yang diatur untuk minimalkan ke system tray, periksa apakah OBS masih berjalan di situ." -AlreadyRunning.LaunchAnyway="Jalankan Saja" +AlreadyRunning.Text="OBS sudah berjalan! Kecuali jika Anda bermaksud melakukan ini, harap matikan semua instansi-instansi OBS yang ada sebelum mencoba menjalankan instansi baru. Jika Anda memiliki OBS yang diatur untuk di minimalkan ke baki sistem, mohon diperiksa apakah OBS masih berjalan atau tidak." +AlreadyRunning.LaunchAnyway="Jalankan Bagaimanapun Juga" ChromeOS.Title="Platform Tidak Didukung" ChromeOS.Text="Tampaknya OBS berjalan di dalam kontainer ChromeOS. Platform ini tidak didukung" -DockCloseWarning.Title="Menutup Jendela Dockable" -DockCloseWarning.Text="Anda baru saja menutup jendela dockable. Jika Anda ingin menampilkannya lagi, gunakan menu Tampilan → Dock pada bar menu." +DockCloseWarning.Title="Menutup Jendela yang Bisa Didok" +DockCloseWarning.Text="Anda baru saja menutup jendela yang bisa di dok. Jika Anda ingin menampilkannya lagi, gunakan menu Tampilan → Dok pada bar menu." -ExtraBrowsers="Dock Browser Kustom" -ExtraBrowsers.Info="Tambahkan dock dengan memberi nama dan URL, lalu klik Terapkan atau Tutup untuk membuka dock. Anda dapat menambah atau menghapus dock kapan saja." -ExtraBrowsers.DockName="Nama dock" +ExtraBrowsers="Dok Browser Kustom" +ExtraBrowsers.Info="Tambahkan dok dengan memberi nama dan URL, lalu klik Terapkan atau Tutup untuk membuka dok. Anda dapat menambah atau menghapus dok kapan saja." +ExtraBrowsers.DockName="Nama dok" -Auth.Authing.Title="Otentikasi..." -Auth.Authing.Text="Otentikasi dengan %1, tunggu sebentar..." -Auth.AuthFailure.Title="Otentikasi Gagal" +Auth.Authing.Title="Mengautentikasi..." +Auth.Authing.Text="Mengautentikasi dengan %1, silahkan tunggu..." +Auth.AuthFailure.Title="Autentikasi Gagal" Auth.AuthFailure.Text="Gagal mengautentikasi dengan %1:\n\n%2: %3" -Auth.InvalidScope.Title="Otentikasi Diperlukan" +Auth.InvalidScope.Title="Autentikasi Diperlukan" Auth.InvalidScope.Text="Persyaratan otentikasi untuk %1 telah berubah. Beberapa fitur mungkin tidak tersedia." Auth.LoadingChannel.Title="Memuat informasi saluran..." -Auth.LoadingChannel.Text="Memuat informasi saluran untuk %1, tunggu sebentar..." +Auth.LoadingChannel.Text="Memuat informasi saluran untuk %1, silahkan tunggu..." Auth.ChannelFailure.Title="Gagal memuat saluran" Auth.ChannelFailure.Text="Gagal memuat informasi saluran untuk %1\n\n%2: %3" -Auth.Chat="Chat" +Auth.Chat="Obrolan" Auth.StreamInfo="Informasi Streaming" -TwitchAuth.Stats="Status Twitch" +TwitchAuth.Stats="Statistik Twitch" TwitchAuth.Feed="Umpan Aktivitas Twitch" -TwitchAuth.TwoFactorFail.Title="Tidak bisa meminta kunci streaming" -TwitchAuth.TwoFactorFail.Text="OBS tidak dapat terhubung ke akun Twitch Anda. Harap pastikan otentikasi dua faktor diatur di pengaturan keamanan Twitch Anda karena ini diperlukan untuk streaming." +TwitchAuth.TwoFactorFail.Title="Tidak dapat meminta kunci streaming" +TwitchAuth.TwoFactorFail.Text="OBS tidak dapat terhubung ke akun Twitch Anda. Mohon pastikan autentikasi dua faktor diatur di Twitch security settings Anda karena ini diperlukan untuk streaming." RestreamAuth.Channels="Streaming Ulang Saluran" Copy.Filters="Salin Filter" Paste.Filters="Tempel Filter" -BrowserPanelInit.Title="Inisialisasi Browser..." -BrowserPanelInit.Text="Inisialisasi browser, tunggu sebentar..." +BrowserPanelInit.Title="Menginisialisasi Browser..." +BrowserPanelInit.Text="Menginisialisasi browser, silahkan tunggu..." BandwidthTest.Region="Wilayah" BandwidthTest.Region.US="Amerika Serikat" @@ -138,7 +139,7 @@ BandwidthTest.Region.EU="Eropa" BandwidthTest.Region.Asia="Asia" BandwidthTest.Region.Other="Lainnya" -Basic.AutoConfig="Layanan Konfigurasi Otomatis" +Basic.AutoConfig="Wisaya Konfigurasi Otomatis" Basic.AutoConfig.ApplySettings="Terapkan Pengaturan" Basic.AutoConfig.StartPage="Informasi Penggunaan" Basic.AutoConfig.StartPage.SubTitle="Tentukan untuk apa Anda ingin menggunakan program ini" @@ -148,18 +149,19 @@ Basic.AutoConfig.StartPage.PrioritizeVirtualCam="Saya hanya akan menggunakan kam Basic.AutoConfig.VideoPage="Pengaturan Video" Basic.AutoConfig.VideoPage.SubTitle="Tentukan pengaturan video yang ingin Anda gunakan" Basic.AutoConfig.VideoPage.BaseResolution.UseCurrent="Gunakan Saat Ini (%1x%2)" -Basic.AutoConfig.VideoPage.BaseResolution.Display="Tampilan %1 (%2x%3)" +Basic.AutoConfig.VideoPage.BaseResolution.Display="Layar %1 (%2x%3)" Basic.AutoConfig.VideoPage.FPS.UseCurrent="Gunakan Saat Ini (%1)" Basic.AutoConfig.VideoPage.FPS.PreferHighFPS="Antara 60 atau 30, tetapi lebih memilih 60 jika memungkinkan" Basic.AutoConfig.VideoPage.FPS.PreferHighRes="Antara 60 atau 30, tetapi lebih memilih beresolusi tinggi" -Basic.AutoConfig.VideoPage.CanvasExplanation="Catatan: Resolusi kanvas (dasar) tidak harus sama dengan resolusi yang akan Anda siarkan atau rekam. Resolusi streaming/rekaman Anda yang sebenarnya dapat diturunkan dari resolusi kanvas untuk mengurangi penggunaan sumber daya atau bitrate yang diperlukan." +Basic.AutoConfig.VideoPage.CanvasExplanation="Catatan: Resolusi kanvas (dasar) tidak harus sama dengan resolusi yang akan Anda siarkan atau rekam. Resolusi streaming/rekaman Anda yang sebenarnya mungkin dapat diturunkan dari resolusi kanvas untuk mengurangi penggunaan sumber daya atau bitrate yang diperlukan." Basic.AutoConfig.StreamPage="Informasi Streaming" Basic.AutoConfig.StreamPage.SubTitle="Silahkan masukkan informasi streaming Anda" Basic.AutoConfig.StreamPage.ConnectAccount="Hubungkan Akun (disarankan)" -Basic.AutoConfig.StreamPage.DisconnectAccount="Putuskan Sambungan Akun" -Basic.AutoConfig.StreamPage.DisconnectAccount.Confirm.Title="Putuskan Sambungan Akun?" +Basic.AutoConfig.StreamPage.DisconnectAccount="Putuskan Akun" +Basic.AutoConfig.StreamPage.DisconnectAccount.Confirm.Title="Putuskan Akun?" Basic.AutoConfig.StreamPage.DisconnectAccount.Confirm.Text="Perubahan ini akan diterapkan segera. Apakah Anda yakin ingin memutuskan koneksi akun Anda?" Basic.AutoConfig.StreamPage.GetStreamKey="Dapatkan Stream Key" +Basic.AutoConfig.StreamPage.MoreInfo="Info lebih lanjut" Basic.AutoConfig.StreamPage.UseStreamKey="Gunakan Stream Key" Basic.AutoConfig.StreamPage.Service="Layanan" Basic.AutoConfig.StreamPage.Service.ShowAll="Tampilkan Semua..." @@ -168,8 +170,8 @@ Basic.AutoConfig.StreamPage.Server="Server" Basic.AutoConfig.StreamPage.StreamKey="Stream Key" Basic.AutoConfig.StreamPage.StreamKey.LinkToSite="(Tautan)" Basic.AutoConfig.StreamPage.PerformBandwidthTest="Perkirakan bitrate dengan uji bandwidth (mungkin perlu beberapa menit)" -Basic.AutoConfig.StreamPage.PreferHardwareEncoding="Lebih memilih pengkodean hardware" -Basic.AutoConfig.StreamPage.PreferHardwareEncoding.ToolTip="Pengkodean Hardware mengurangi sebagian besar pemakaian CPU, tetapi mungkin memerlukan bitrate lebih banyak untuk mendapatkan kualitas yang sama." +Basic.AutoConfig.StreamPage.PreferHardwareEncoding="Lebih memilih enkoding perangkat keras" +Basic.AutoConfig.StreamPage.PreferHardwareEncoding.ToolTip="Enkoding Perangkat Keras mengurangi sebagian besar pemakaian CPU, tetapi mungkin memerlukan bitrate lebih besar untuk mendapatkan kualitas yang sama." Basic.AutoConfig.StreamPage.StreamWarning.Title="Peringatan streaming" Basic.AutoConfig.StreamPage.StreamWarning.Text="Tes bandwidth akan melakukan streaming data video acak tanpa audio ke saluran Anda. Jika bisa, disarankan untuk menonaktifkan sementara menyimpan video stream dan atur streaming ke pribadi hingga tes selesai. Lanjutkan?" Basic.AutoConfig.TestPage="Hasil Akhir" @@ -364,8 +366,8 @@ Deinterlacing.Yadif2x="Yadif 2x" Deinterlacing.TopFieldFirst="Bagian Atas Dahulu" Deinterlacing.BottomFieldFirst="Bagian Bawah Dahulu" -VolControl.SliderUnmuted="Penggeser volume untuk '%1': %2" -VolControl.SliderMuted="Penggeser volume untuk '%1': %2 (saat ini dibisukan)" +VolControl.SliderUnmuted="Penggeser volume untuk '%1':" +VolControl.SliderMuted="Penggeser volume untuk '%1': (saat ini dibisukan)" VolControl.Mute="Bisukan '%1'" VolControl.Properties="Properti '%1'" @@ -381,6 +383,7 @@ Basic.Main.RenameSceneCollection.Title="Ubah Nama Koleksi Adegan" AddProfile.Title="Tambah Profil" AddProfile.Text="Silakan masukkan nama profil" +AddProfile.WizardCheckbox="Tunjukkan Konfigurasi Otomatis" RenameProfile.Title="Ubah Nama Profil" @@ -395,6 +398,11 @@ Basic.SourceSelect.CreateNew="Buat baru" Basic.SourceSelect.AddExisting="Tambahkan Yang Ada" Basic.SourceSelect.AddVisible="Buat sumber terlihat" +Basic.Main.Sources.Visibility="Tampilan" +Basic.Main.Sources.VisibilityDescription="Kontrol tampilan '%1' di kanvas" +Basic.Main.Sources.Lock="Kunci" +Basic.Main.Sources.LockDescription="Kunci posisi dan skala '%1' di kanvas" + Basic.PropertiesWindow="Properti '%1'" Basic.PropertiesWindow.AutoSelectFormat="%1 (pilih-otomatis: %2)" Basic.PropertiesWindow.SelectColor="Pilih warna" @@ -485,7 +493,7 @@ Basic.Main.ShowContextBar="Tampilkan Toolbar Sumber" Basic.Main.HideContextBar="Sembunyikan Toolbar Sumber" Basic.Main.StopVirtualCam="Hentikan Kamera Virtual" Basic.Main.Group="Kelompok %1" -Basic.Main.GroupItems="Kelompokkan Item Terpilih" +Basic.Main.GroupItems="Kelompokkan Item yang Dipilih" Basic.Main.Ungroup="Pisahkan Kelompok" Basic.Main.GridMode="Mode Grid" Basic.Main.ListMode="Mode Daftar" @@ -582,10 +590,10 @@ Basic.Settings.General.Language="Bahasa" Basic.Settings.General.EnableAutoUpdates="Otomatis memeriksa pembaruan saat startup" Basic.Settings.General.OpenStatsOnStartup="Buka dialog statistik saat startup" Basic.Settings.General.WarnBeforeStartingStream="Tampilkan dialog konfirmasi saat memulai streaming" -Basic.Settings.General.WarnBeforeStoppingStream="Tampilkan dialog konfirmasi saat menghentikan streaming" -Basic.Settings.General.WarnBeforeStoppingRecord="Tampilkan dialog konfirmasi saat menghentikan rekaman" +Basic.Settings.General.WarnBeforeStoppingStream="Tampilkan dialog konfirmasi saat berhenti streaming" +Basic.Settings.General.WarnBeforeStoppingRecord="Tampilkan dialog konfirmasi saat berhenti merekam" Basic.Settings.General.Projectors="Proyektor" -Basic.Settings.General.HideProjectorCursor="Sembunyikan cursor di Proyektor" +Basic.Settings.General.HideProjectorCursor="Sembunyikan kursor di Proyektor" Basic.Settings.General.ProjectorAlwaysOnTop="Jadikan proyektor selalu di atas" Basic.Settings.General.Snapping="Sentakan Penjajaran Sumber" Basic.Settings.General.ScreenSnapping="Sentakkan Sumber ke tepi layar" @@ -608,7 +616,7 @@ Basic.Settings.General.Importers="Pengimpor" Basic.Settings.General.AutomaticCollectionSearch="Cari lokasi yang diketahui untuk koleksi adegan saat mengimpor" Basic.Settings.General.SwitchOnDoubleClick="Transisi ke adegan ketika diklik dua kali" Basic.Settings.General.StudioPortraitLayout="Aktifkan tata letak potret/vertikal" -Basic.Settings.General.TogglePreviewProgramLabels="Tampilkan label preview/rogram" +Basic.Settings.General.TogglePreviewProgramLabels="Tampilkan label preview/program" Basic.Settings.General.Multiview="Multiview" Basic.Settings.General.Multiview.MouseSwitch="Klik untuk beralih antar adegan" Basic.Settings.General.Multiview.DrawSourceNames="Tampilkan nama adegan" @@ -634,13 +642,19 @@ Basic.Settings.Stream.StreamSettingsWarning="Buka Pengaturan" Basic.Settings.Stream.MissingUrlAndApiKey="URL dan Stream Key tidak ada.\n\nBuka pengaturan untuk memasukkan URL dan Stream Key di tab 'streaming'." Basic.Settings.Stream.MissingUrl="URL tidak ada.\n\nBuka pengaturan untuk memasukkan URL di tab 'Streaming'." Basic.Settings.Stream.MissingStreamKey="Stream key tidak ada.\n\nBuka pengaturan untuk memasukkan stream key di tab 'Streaming'." +Basic.Settings.Stream.IgnoreRecommended="Abaikan rekomendasi pengaturan layanan streaming" +Basic.Settings.Stream.IgnoreRecommended.Warn.Title="Mengganti pengaturan yang direkomendasi" +Basic.Settings.Stream.IgnoreRecommended.Warn.Text="Peringatan: Mengabaikan batasan layanan dapat menurunkan kualitas streaming atau mencegah Anda melakukan streaming. \n\nLanjutkan?" +Basic.Settings.Stream.Recommended.MaxVideoBitrate="Video Bitrate Maksimal: %1 kbps" +Basic.Settings.Stream.Recommended.MaxAudioBitrate="Audio Bitrate Maksimal: %1 kbps" +Basic.Settings.Stream.Recommended.MaxResolution="Resolusi Maksimal: %1" +Basic.Settings.Stream.Recommended.MaxFPS="FPS Maksimal: %1" Basic.Settings.Output="Output" Basic.Settings.Output.Format="Format Rekaman" Basic.Settings.Output.Encoder="Enkoder" Basic.Settings.Output.SelectDirectory="Pilih Direktori Rekaman" Basic.Settings.Output.SelectFile="Pilih File Rekaman" -Basic.Settings.Output.EnforceBitrate="Tegakkan batas bitrate layanan streaming" Basic.Settings.Output.DynamicBitrate="Ubah bitrate secara dinamis untuk mengelola gangguan" Basic.Settings.Output.DynamicBitrate.Beta="Ubah bitrate secara dinamis untuk mengelola gangguan (Beta)" Basic.Settings.Output.DynamicBitrate.TT="Alih-alih men-dropkan frame untuk mengurangi gangguan, secara dinamis mengubah bitrate dengan cepat.\n\nPerhatikan bahwa ini dapat meningkatkan waktu delay bagi penoton jika ada gangguan tiba-tiba yang signifikan.\nKetika bitrate turun, diperlukan waktu beberapa menit untuk memulihkannya.\n\nSaat ini hanya didukung untuk RTMP." @@ -659,20 +673,25 @@ Basic.Settings.Output.Simple.SavePath="Jalur Rekaman" Basic.Settings.Output.Simple.RecordingQuality="Kualitas Rekaman" Basic.Settings.Output.Simple.RecordingQuality.Stream="Sama seperti streaming" Basic.Settings.Output.Simple.RecordingQuality.Small="Kualitas Tinggi, Ukuran File Sedang" -Basic.Settings.Output.Simple.RecordingQuality.HQ="Kualitas Tidak Bisa Dibedakan, Ukuran File Besar" +Basic.Settings.Output.Simple.RecordingQuality.HQ="Kualitas Tak Dapat Dibedakan, Ukuran File Besar" Basic.Settings.Output.Simple.RecordingQuality.Lossless="Kualitas Lossless, Ukuran File Sangat Besar" -Basic.Settings.Output.Simple.Warn.VideoBitrate="Peringatan: Bitrate video streaming akan diatur ke %1, yang merupakan batas atas untuk layanan streaming saat ini. Jika Anda yakin ingin lebih dari %1, aktifkan opsi enkoder tingkat lanjut dan hapus centang \"Paksa batas bitrate layanan streaming\"." -Basic.Settings.Output.Simple.Warn.AudioBitrate="Peringatan: Bitrate audio streaming akan diatur ke %1, yang merupakan batas atas untuk layanan streaming saat ini. Jika Anda yakin ingin lebih dari %1, aktifkan opsi enkoder tingkat lanjut dan hapus centang \"Tegakkan batas bitrate layanan streaming\"." +Basic.Settings.Output.Simple.Warn.VideoBitrate="Peringatan: Bitrate video streaming akan diatur ke %1, yang merupakan batas atas untuk layanan streaming saat ini." +Basic.Settings.Output.Simple.Warn.AudioBitrate="Peringatan: Bitrate audio streaming akan diatur ke %1, yang merupakan batas atas untuk layanan streaming saat ini." Basic.Settings.Output.Simple.Warn.CannotPause="Peringatan: Rekaman tidak dapat dijeda jika kualitas rekaman diatur ke \"Sama seperti streaming\"." Basic.Settings.Output.Simple.Warn.Encoder="Peringatan: Perekaman dengan enkoder software pada kualitas yang berbeda dengan streaming akan membutuhkan pemakaian CPU ekstra jika Anda melakukan streaming dan merekam bersamaan." Basic.Settings.Output.Simple.Warn.Lossless="Peringatan: Kualitas lossless menghasilkan ukuran file yang sangat besar! Kualitas lossless dapat menggunakan ruang disk hingga 7 gigabyte per menit pada resolusi dan framerate tinggi. Lossless tidak disarankan saat merekam lama kecuali Anda memiliki ruang disk yang sangat besar." Basic.Settings.Output.Simple.Warn.Lossless.Msg="Apakah Anda yakin ingin menggunakan kualitas lossless?" Basic.Settings.Output.Simple.Warn.Lossless.Title="Peringatan kualitas lossless!" 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.Hardware.QSV="Perangkat Keras (QSV)" +Basic.Settings.Output.Simple.Encoder.Hardware.AMD="Perangkat Keras (AMD)" +Basic.Settings.Output.Simple.Encoder.Hardware.NVENC="Perangkat Keras (NVENC)" Basic.Settings.Output.Simple.Encoder.SoftwareLowCPU="Perangkat lunak (x264 preset penggunaan CPU rendah, ukuran file meningkat)" +Basic.Settings.Output.Simple.TwitchVodTrack="Jalur VOD Twitch (Menggunakan Jalur 2)" +Basic.Settings.Output.Warn.EnforceResolutionFPS.Title="Resolusi/Framerate tidak cocok" +Basic.Settings.Output.Warn.EnforceResolutionFPS.Msg="Layanan streaming ini tidak mendukung resolusi dan/atau framerate anda saat ini. Ini akan diganti ke nilai cocok paling dekat:\n\n%1\n\nApa anda ingin melanjutkan?" +Basic.Settings.Output.Warn.EnforceResolutionFPS.Resolution="Resolusi: %1" +Basic.Settings.Output.Warn.EnforceResolutionFPS.FPS="FPS: %1" Basic.Settings.Output.VideoBitrate="Bitrate Video" Basic.Settings.Output.AudioBitrate="Bitrate Audio" Basic.Settings.Output.Reconnect="Hubungkan Kembali Secara Otomatis" @@ -687,21 +706,22 @@ Basic.Settings.Output.NoSpaceFileName="Buat Nama File tanpa Spasi" Basic.Settings.Output.Adv.Rescale="Skala Ulang Output" Basic.Settings.Output.Adv.AudioTrack="Trek Audio" Basic.Settings.Output.Adv.Streaming="Streaming" -Basic.Settings.Output.Adv.ApplyServiceSettings="Tegakkan pengaturan enkoder layanan streaming" Basic.Settings.Output.Adv.Audio.Track1="Trek 1" Basic.Settings.Output.Adv.Audio.Track2="Trek 2" Basic.Settings.Output.Adv.Audio.Track3="Trek 3" Basic.Settings.Output.Adv.Audio.Track4="Trek 4" Basic.Settings.Output.Adv.Audio.Track5="Trek 5" Basic.Settings.Output.Adv.Audio.Track6="Trek 6" +Basic.Settings.Output.Adv.TwitchVodTrack="Jalur VOD Twitch" Basic.Settings.Output.Adv.Recording="Rekaman" +Basic.Settings.Output.Adv.Recording.RecType="Type Rekaman" Basic.Settings.Output.Adv.Recording.Type="Tipe" Basic.Settings.Output.Adv.Recording.Type.Standard="Standar" Basic.Settings.Output.Adv.Recording.Type.FFmpegOutput="Output Kustom (FFmpeg)" Basic.Settings.Output.Adv.Recording.UseStreamEncoder="(Gunakan enkoder streaming)" Basic.Settings.Output.Adv.Recording.Filename="Format Nama File" -Basic.Settings.Output.Adv.Recording.OverwriteIfExists="Timpa jika file sudah ada" +Basic.Settings.Output.Adv.Recording.OverwriteIfExists="Timpa file yang sudah ada" Basic.Settings.Output.Adv.FFmpeg.Type="Jenis output FFmpeg" Basic.Settings.Output.Adv.FFmpeg.Type.URL="Output ke URL" Basic.Settings.Output.Adv.FFmpeg.Type.RecordToFile="Output ke File" @@ -725,7 +745,7 @@ Basic.Settings.Output.Adv.FFmpeg.GOPSize="Interval keyframe (frame)" Basic.Settings.Output.Adv.FFmpeg.IgnoreCodecCompat="Tampilkan semua kodek (bahkan jika berpotensi tidak kompatibel)" Screenshot="Screenshot Output" -Screenshot.SourceHotkey="Screenshot Sumber Terpilih" +Screenshot.SourceHotkey="Screenshot Sumber yang Dipilih" Screenshot.StudioProgram="Screenshot (Program)" Screenshot.Preview="Screenshot (Preview)" Screenshot.Scene="Screenshot (Adegan)" @@ -752,9 +772,9 @@ Basic.Settings.Video.InvalidResolution="Nilai resolusi tidak valid. Harus [lebar Basic.Settings.Video.CurrentlyActive="Output video saat ini sedang aktif. Matikan semua output untuk mengubah pengaturan video." Basic.Settings.Video.DisableAero="Matikan Aero" -Basic.Settings.Video.DownscaleFilter.Bilinear="Bilinear (Tercepat, tapi ngeblur jika scaling)" -Basic.Settings.Video.DownscaleFilter.Bicubic="Bicubic (scaling tajam, 16 sampel)" -Basic.Settings.Video.DownscaleFilter.Lanczos="Lamczos (scaling tajam, 36 sampel)" +Basic.Settings.Video.DownscaleFilter.Bilinear="Bilinear (Tercepat, tetapi buram jika scaling)" +Basic.Settings.Video.DownscaleFilter.Bicubic="Bikubik (scaling tajam, 16 sampel)" +Basic.Settings.Video.DownscaleFilter.Lanczos="Lanczos (scaling tajam, 36 sampel)" Basic.Settings.Video.DownscaleFilter.Area="Area (Jumlah tertimbang, 4/6/9 sampel)" Basic.Settings.Audio="Audio" @@ -823,16 +843,21 @@ Basic.AdvAudio="Properti Audio Lanjutan" Basic.AdvAudio.ActiveOnly="Sumber Aktif Saja" Basic.AdvAudio.Name="Nama" Basic.AdvAudio.Volume="Volume" +Basic.AdvAudio.VolumeSource="Volume untuk '%1'" Basic.AdvAudio.Mono="Mono" +Basic.AdvAudio.MonoSource="Mono Downmix untuk '%1\"" Basic.AdvAudio.Balance="Keseimbangan" -Basic.AdvAudio.SyncOffset="Sinkronkan Offset" +Basic.AdvAudio.BalanceSource="Saldo untuk '%1'" +Basic.AdvAudio.SyncOffset="Offset Sinkronisasi" +Basic.AdvAudio.SyncOffsetSource="Offset Sinkronisasi untuk '%1'" Basic.AdvAudio.Monitoring="Monitoring Audio" Basic.AdvAudio.Monitoring.None="Monitor Mati" Basic.AdvAudio.Monitoring.MonitorOnly="Monitor Saja (bisukan output)" Basic.AdvAudio.Monitoring.Both="Monitor dan Output" +Basic.AdvAudio.MonitoringSource="Pemantauan Audio untuk '%1'" Basic.AdvAudio.AudioTracks="Trek" -Basic.Settings.Hotkeys="Hotkey" +Basic.Settings.Hotkeys="Pintasan" Basic.Settings.Hotkeys.Pair="Kombinasi tombol yang berbagi dengan '%1' bertindak sebagai pengalih" Basic.Settings.Hotkeys.Filter="Filter" @@ -898,12 +923,12 @@ FinalScene.Text="Harus ada setidaknya satu adegan." NoSources.Title="Tidak Ada Sumber" NoSources.Text="Sepertinya Anda belum menambah sumber video apa pun, jadi Anda hanya akan menghasilkan layar kosong. Anda yakin ingin melakukan ini?" NoSources.Text.AddSource="Anda dapat menambahkan sumber dengan mengklik ikon + di bawah kotak Sumber di jendela utama kapan saja." -NoSources.Label="Anda tidak memiliki sumber apapun.\nKlik tombol + di bawah ini,\natau klik kanan disini untuk menambahkannya." +NoSources.Label="Anda tidak memiliki sumber apapun.\nKlik tombol + di bawah ini,\natau klik kanan disini untuk menambahkan." ChangeBG="Atur Warna" CustomColor="Warna Kustom" -BrowserSource.EnableHardwareAcceleration="Aktifkan Akselerasi Hardware Sumber Browser" +BrowserSource.EnableHardwareAcceleration="Aktifkan Akselerasi Perangkat Keras Sumber Browser" About="Tentang" About.Info="OBS Studio adalah perangkat lunak perekam video dan live streaming gratis dan open source." @@ -936,7 +961,7 @@ Importer.AutomaticCollectionText="OBS dapat menemukan koleksi adegan yang dapat Restart="Mulai Ulang" NeedsRestart="OBS Studio perlu dimulai ulang. Apakah Anda ingin melakukannya sekarang?" -ContextBar.NoSelectedSource="Tidak ada sumber terpilih" +ContextBar.NoSelectedSource="Tidak ada sumber yang dipilih" ContextBar.ResetTransform="Reset Transformasi" ContextBar.FitToCanvas="Pas dengan Kanvas" diff --git a/UI/data/locale/ig-NG.ini b/UI/data/locale/ig-NG.ini index d63dca1..498dae5 100644 --- a/UI/data/locale/ig-NG.ini +++ b/UI/data/locale/ig-NG.ini @@ -107,5 +107,6 @@ Name="Aha" + diff --git a/UI/data/locale/it-IT.ini b/UI/data/locale/it-IT.ini index 8befe04..1599c2a 100644 --- a/UI/data/locale/it-IT.ini +++ b/UI/data/locale/it-IT.ini @@ -161,6 +161,7 @@ Basic.AutoConfig.StreamPage.DisconnectAccount="Disconnetti l'account" Basic.AutoConfig.StreamPage.DisconnectAccount.Confirm.Title="Vuoi disconnettere l'account?" Basic.AutoConfig.StreamPage.DisconnectAccount.Confirm.Text="Questa modifica verrà applicata immediatamente. Sei sicuro di voler disconnettere il tuo account?" Basic.AutoConfig.StreamPage.GetStreamKey="Ottieni Chiave Stream" +Basic.AutoConfig.StreamPage.MoreInfo="Altre Informazioni" Basic.AutoConfig.StreamPage.UseStreamKey="Utilizza il codice delle dirette" Basic.AutoConfig.StreamPage.Service="Servizio" Basic.AutoConfig.StreamPage.Service.ShowAll="Mostra tutti..." @@ -365,8 +366,8 @@ Deinterlacing.Yadif2x="Yadif ×2" Deinterlacing.TopFieldFirst="Priorità nei livelli superiori" Deinterlacing.BottomFieldFirst="Priorità nei livelli inferiori" -VolControl.SliderUnmuted="Barra del volume per «%1»: %2" -VolControl.SliderMuted="Barra del volume per «%1»: %2 (attualmente silenziato)" +VolControl.SliderUnmuted="Barra del volume per «%1»:" +VolControl.SliderMuted="Barra del volume per «%1»: (attualmente silenziato)" VolControl.Mute="Silenzia «%1'»" VolControl.Properties="Proprietà di «%1»" @@ -382,6 +383,7 @@ Basic.Main.RenameSceneCollection.Title="Rinomina della collezione di scene" AddProfile.Title="Aggiunta di un profilo" AddProfile.Text="Digita il nome del profilo" +AddProfile.WizardCheckbox="Mostra procedura guidata di configurazione automatica" RenameProfile.Title="Rinomina del profilo" @@ -396,6 +398,11 @@ Basic.SourceSelect.CreateNew="Crea una nuova fonte" Basic.SourceSelect.AddExisting="Aggiungine una esistente" Basic.SourceSelect.AddVisible="Rendi visibile la fonte" +Basic.Main.Sources.Visibility="Visibilità" +Basic.Main.Sources.VisibilityDescription="Controlla la visibilità di «%1» nella superficie" +Basic.Main.Sources.Lock="Blocca" +Basic.Main.Sources.LockDescription="Blocca la posizione e la scala di «%1» nella superficie" + Basic.PropertiesWindow="Proprietà di «%1»" Basic.PropertiesWindow.AutoSelectFormat="%1 (autoseleziona: %2)" Basic.PropertiesWindow.SelectColor="Seleziona il colore" @@ -635,13 +642,19 @@ Basic.Settings.Stream.StreamSettingsWarning="Apri Impostazioni" Basic.Settings.Stream.MissingUrlAndApiKey="URL e Codice delle dirette sono mancanti.\n\nApri le impostazioni per inserire URL e codice delle dirette nella scheda 'stream'." Basic.Settings.Stream.MissingUrl="URL dello stream mancante.\n\nApri le impostazione per inserire l'URL nella scheda \"Stream\"." Basic.Settings.Stream.MissingStreamKey="Chiave stream mancante.\n\nApri le impostazioni per inserire la chiave stream nella scheda \"Stream\"." +Basic.Settings.Stream.IgnoreRecommended="Ignora opzioni raccomandate di streaming" +Basic.Settings.Stream.IgnoreRecommended.Warn.Title="Ignora le impostazioni raccomandate" +Basic.Settings.Stream.IgnoreRecommended.Warn.Text="Attenzione: ignorare le limitazioni del servizio può degradare la qualità o impedire completamente lo streaming.\n\nContinuare?" +Basic.Settings.Stream.Recommended.MaxVideoBitrate="Bitrate video massimo: %1 kbps" +Basic.Settings.Stream.Recommended.MaxAudioBitrate="Bitrate audio massimo: %1 kbps" +Basic.Settings.Stream.Recommended.MaxResolution="Risoluzione massima: %1" +Basic.Settings.Stream.Recommended.MaxFPS="FPS Massimi: %1" Basic.Settings.Output="Uscita" Basic.Settings.Output.Format="Formato di registrazione" Basic.Settings.Output.Encoder="Codifica" Basic.Settings.Output.SelectDirectory="Seleziona la cartella di registrazione" Basic.Settings.Output.SelectFile="Seleziona il file di registrazione" -Basic.Settings.Output.EnforceBitrate="Non superare i limiti di velocità in bit del servizio di dirette" Basic.Settings.Output.DynamicBitrate="Cambia in modo dinamico il bitrate per gestire la congestione" Basic.Settings.Output.DynamicBitrate.Beta="Cambia in modo dinamico il bitrate per gestire la congestione (Beta)" Basic.Settings.Output.DynamicBitrate.TT="Invece di saltare fotogrammi per ridurre la congestione, cambia dinamicamente il bitrate al volo.\n\nNota che questo potrebbe aumentare il ritardo agli spettatori se c'è una significante congestione improvvisa.\nQuando il bitrate diminuisce, potrebbero volerci fino ad alcuni minuti per ripristinarlo.\n\nAttualmente è solo supportato per RTMP." @@ -662,8 +675,8 @@ Basic.Settings.Output.Simple.RecordingQuality.Stream="La stessa della diretta" Basic.Settings.Output.Simple.RecordingQuality.Small="Alta qualità, dimensioni dei file medie" Basic.Settings.Output.Simple.RecordingQuality.HQ="Qualità indistinguibile, dimensioni dei file elevate" Basic.Settings.Output.Simple.RecordingQuality.Lossless="Senza perdita di qualità (lossless), dimensioni dei file enormi" -Basic.Settings.Output.Simple.Warn.VideoBitrate="Attenzione: la velocità in bit video della diretta verrà impostata a %1, che è il limite più alto per il servizio di dirette attuale. Se sei sicuro di voler superare il valore %1, attiva le impostazioni avanzate della codifica e deseleziona «Non superare i limiti di velocità in bit del servizio di dirette»." -Basic.Settings.Output.Simple.Warn.AudioBitrate="Attenzione: la velocità in bit audio della diretta verrà impostata a %1, che è il limite più alto per il servizio di dirette attuale. Se sei sicuro di voler superare il valore %1, attiva le impostazioni avanzate della codifica e deseleziona «Non superare i limiti di velocità in bit del servizio di dirette»." +Basic.Settings.Output.Simple.Warn.VideoBitrate="Attenzione: il bitrate video in streaming sarà impostato a %1, che è il limite superiore per il servizio di streaming corrente." +Basic.Settings.Output.Simple.Warn.AudioBitrate="Attenzione: il bitrate audio in streaming sarà impostato a %1, che è il limite superiore per il servizio di streaming corrente." Basic.Settings.Output.Simple.Warn.CannotPause="Attenzione: Le registrazioni non possono essere sospese se la qualità di registrazione è impostata su \"Lo stesso del flusso\"." Basic.Settings.Output.Simple.Warn.Encoder="Attenzione: registrare con una codifica software a una qualità diversa dalla diretta richiederà un utilizzo aggiuntivo della CPU se esegui dirette e registri allo stesso tempo." Basic.Settings.Output.Simple.Warn.Lossless="Attenzione: la qualità lossless genera file estremamente grandi! Può occupare fino a 7 gigabyte di spazio al minuto con alte risoluzioni e framerate. Non è consigliata per lunghe registrazioni a meno che tu non abbia molto spazio disponibile sul disco rigido." @@ -674,6 +687,11 @@ 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, preset con basso utilizzo della CPU, aumenta le dimensioni dei file)" +Basic.Settings.Output.Simple.TwitchVodTrack="Incrocia la traccia VOD (usa traccia 2)" +Basic.Settings.Output.Warn.EnforceResolutionFPS.Title="Risoluzione/framerate incompatibili" +Basic.Settings.Output.Warn.EnforceResolutionFPS.Msg="Questo servizio di streaming non supporta la risoluzione e/o il framerate in uscita correnti. Verranno cambiati al valore più vicino compatibile:\n\n%1\n\nContinuare?" +Basic.Settings.Output.Warn.EnforceResolutionFPS.Resolution="Risoluzione: %1" +Basic.Settings.Output.Warn.EnforceResolutionFPS.FPS="FPS: %1" Basic.Settings.Output.VideoBitrate="Velocità in bit video" Basic.Settings.Output.AudioBitrate="Velocità in bit audio" Basic.Settings.Output.Reconnect="Riconnessione automatica" @@ -688,15 +706,16 @@ Basic.Settings.Output.NoSpaceFileName="Genera il nome dei file senza spazi" Basic.Settings.Output.Adv.Rescale="Riscala l'uscita" Basic.Settings.Output.Adv.AudioTrack="Traccia audio" Basic.Settings.Output.Adv.Streaming="Dirette" -Basic.Settings.Output.Adv.ApplyServiceSettings="Imponi le impostazioni di codifica del servizio delle dirette" Basic.Settings.Output.Adv.Audio.Track1="Traccia 1" Basic.Settings.Output.Adv.Audio.Track2="Traccia 2" Basic.Settings.Output.Adv.Audio.Track3="Traccia 3" Basic.Settings.Output.Adv.Audio.Track4="Traccia 4" Basic.Settings.Output.Adv.Audio.Track5="Traccia 5" Basic.Settings.Output.Adv.Audio.Track6="Traccia 6" +Basic.Settings.Output.Adv.TwitchVodTrack="Traccia VOD Twitch" Basic.Settings.Output.Adv.Recording="Registrazioni" +Basic.Settings.Output.Adv.Recording.RecType="Tipo di registrazione" Basic.Settings.Output.Adv.Recording.Type="Tipo" Basic.Settings.Output.Adv.Recording.Type.Standard="Standard" Basic.Settings.Output.Adv.Recording.Type.FFmpegOutput="Uscita personalizzata (FFmpeg)" @@ -824,13 +843,18 @@ Basic.AdvAudio="Proprietà audio avanzate" Basic.AdvAudio.ActiveOnly="Solo Fonti Attive" Basic.AdvAudio.Name="Nome" Basic.AdvAudio.Volume="Volume" +Basic.AdvAudio.VolumeSource="Volume per «%1»" Basic.AdvAudio.Mono="Mono" +Basic.AdvAudio.MonoSource="Mix in mono per «%1»" Basic.AdvAudio.Balance="Bilanciamento" +Basic.AdvAudio.BalanceSource="Bilanciamento per «%1»" Basic.AdvAudio.SyncOffset="Ritardo per la sincronizzazione" +Basic.AdvAudio.SyncOffsetSource="Scostamento di sincronizzazione per «%1»" Basic.AdvAudio.Monitoring="Monitoraggio audio" Basic.AdvAudio.Monitoring.None="Disattivato" Basic.AdvAudio.Monitoring.MonitorOnly="Solo monitoraggio (uscita audio nel file disattivata)" Basic.AdvAudio.Monitoring.Both="Monitora l'audio e invia all'uscita" +Basic.AdvAudio.MonitoringSource="Monitoraggio audio per «%1»" Basic.AdvAudio.AudioTracks="Tracce" Basic.Settings.Hotkeys="Scorciatoie" diff --git a/UI/data/locale/ja-JP.ini b/UI/data/locale/ja-JP.ini index 1f8d781..b7aba39 100644 --- a/UI/data/locale/ja-JP.ini +++ b/UI/data/locale/ja-JP.ini @@ -161,6 +161,7 @@ Basic.AutoConfig.StreamPage.DisconnectAccount="アカウントを切断" Basic.AutoConfig.StreamPage.DisconnectAccount.Confirm.Title="アカウントを切断しますか?" Basic.AutoConfig.StreamPage.DisconnectAccount.Confirm.Text="この変更はすぐに適用されます。 アカウントを切断してもよろしいですか?" Basic.AutoConfig.StreamPage.GetStreamKey="ストリームキーを取得" +Basic.AutoConfig.StreamPage.MoreInfo="詳細情報" Basic.AutoConfig.StreamPage.UseStreamKey="ストリームキーを使用" Basic.AutoConfig.StreamPage.Service="サービス" Basic.AutoConfig.StreamPage.Service.ShowAll="すべて表示..." @@ -365,8 +366,6 @@ Deinterlacing.Yadif2x="Yadif 2x" Deinterlacing.TopFieldFirst="トップフィールドが先" Deinterlacing.BottomFieldFirst="ボトムフィールドが先" -VolControl.SliderUnmuted="'%1' の音量スライダー: %2" -VolControl.SliderMuted="'%1' の音量スライダー: %2 (現在ミュート)" VolControl.Mute="'%1' をミュート" VolControl.Properties="'%1' のプロパティ" @@ -382,6 +381,7 @@ Basic.Main.RenameSceneCollection.Title="シーンコレクションの名前を AddProfile.Title="プロファイルを追加" AddProfile.Text="プロファイルの名前を入力してください" +AddProfile.WizardCheckbox="自動構成ウィザードを表示する" RenameProfile.Title="プロファイルの名前を変更" @@ -396,6 +396,8 @@ Basic.SourceSelect.CreateNew="新規作成" Basic.SourceSelect.AddExisting="既存を追加" Basic.SourceSelect.AddVisible="ソースを表示" +Basic.Main.Sources.Lock="ロック" + Basic.PropertiesWindow="'%1' のプロパティ" Basic.PropertiesWindow.AutoSelectFormat="%1 (自動選択: %2)" Basic.PropertiesWindow.SelectColor="色を選択" @@ -635,13 +637,19 @@ Basic.Settings.Stream.StreamSettingsWarning="設定を開く" Basic.Settings.Stream.MissingUrlAndApiKey="配信用URLとストリームキーがありません。\n\n設定の[配信]タブで配信用URLとストリームキーが入力できます。" Basic.Settings.Stream.MissingUrl="配信用URLがありません。\n\n設定の[配信]タブで配信用URLが入力できます。" Basic.Settings.Stream.MissingStreamKey="ストリームキーがありません。\n\n設定の[配信]タブでストリームキーが入力できます。" +Basic.Settings.Stream.IgnoreRecommended="配信サービスの推奨事項設定を無視する" +Basic.Settings.Stream.IgnoreRecommended.Warn.Title="推奨設定を上書きする" +Basic.Settings.Stream.IgnoreRecommended.Warn.Text="警告: 配信サービスの制限を無視すると、配信の品質が低下したり、配信ができなくなったりする可能性があります。\n\n続行しますか?" +Basic.Settings.Stream.Recommended.MaxVideoBitrate="最大映像ビットレート: %1 kbps" +Basic.Settings.Stream.Recommended.MaxAudioBitrate="最大音声ビットレート: %1 kbps" +Basic.Settings.Stream.Recommended.MaxResolution="最大解像度: %1" +Basic.Settings.Stream.Recommended.MaxFPS="最大FPS: %1" 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.DynamicBitrate="輻輳を管理するためにビットレートを動的に変更する" Basic.Settings.Output.DynamicBitrate.Beta="輻輳を管理するためにビットレートを動的に変更する (ベータ版)" Basic.Settings.Output.DynamicBitrate.TT="フレームをドロップして輻輳を減らす代わりに、ビットレートを動的に変更します。\n\n突然の大幅な輻輳が発生した場合には視聴者の遅延が増大する可能性があることに注意してください。\nビットレートが低下すると、復元に数分かかることがあります。\n\n現時点ではRTMPでのみサポートされています。" @@ -662,8 +670,8 @@ 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.VideoBitrate="警告: 配信の映像のビットレートは、現行の配信サービスの上限である%1に設定されます。" +Basic.Settings.Output.Simple.Warn.AudioBitrate="警告: 配信の音声のビットレートは、現行の配信サービスの上限である%1に設定されます。" Basic.Settings.Output.Simple.Warn.CannotPause="警告:録画品質が「配信と同品質」に設定されている場合は録画を一時停止することはできません。" Basic.Settings.Output.Simple.Warn.Encoder="警告: 配信と録画を同時に行う場合に配信と異なる品質でソフトウェアエンコーダで録画する場合にはさらなるCPU 使用率が必要になります。" Basic.Settings.Output.Simple.Warn.Lossless="警告: 無損失品質は途方もなく大きなファイルサイズになります!無損失品質は高解像度と高フレーム レートで 1 分あたり7 ギガバイト以上のディスク容量を使用します。 非常に大量のディスクの空き容量がない場合の長時間録画には無損失設定の使用はお勧めしません。" @@ -674,6 +682,11 @@ 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.Simple.TwitchVodTrack="Twitch VODトラック (トラック 2を使用)" +Basic.Settings.Output.Warn.EnforceResolutionFPS.Title="互換性のない解像度/フレームレート" +Basic.Settings.Output.Warn.EnforceResolutionFPS.Msg="この配信サービスは現在の出力解像度やフレームレートをサポートしていません。それらは最も近い互換性のある値に変更されます:\n\n%1\n\n続行しますか?" +Basic.Settings.Output.Warn.EnforceResolutionFPS.Resolution="解像度: %1" +Basic.Settings.Output.Warn.EnforceResolutionFPS.FPS="FPS: %1" Basic.Settings.Output.VideoBitrate="映像ビットレート" Basic.Settings.Output.AudioBitrate="音声ビットレート" Basic.Settings.Output.Reconnect="自動的に再接続" @@ -688,13 +701,13 @@ 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.Audio.Track5="トラック 5" Basic.Settings.Output.Adv.Audio.Track6="トラック 6" +Basic.Settings.Output.Adv.TwitchVodTrack="Twitch VODトラック" Basic.Settings.Output.Adv.Recording="録画" Basic.Settings.Output.Adv.Recording.Type="種別" @@ -931,7 +944,7 @@ Importer.HelpText="OBSまたは他の対応アプリからエクスポートさ Importer.Path="コレクションのパス" Importer.Program="検出されたアプリケーション" Importer.AutomaticCollectionPrompt="シーンコレクションの自動検索" -Importer.AutomaticCollectionText="対応するサードパーティプログラムからインポート可能なシーンコレクションを自動的に見つけることができます。 シーンコレクションを自動検索しますか?\n\nこれは後で設定 > 一般 > インポーターで変更できます。" +Importer.AutomaticCollectionText="OBSは対応するサードパーティプログラムからインポート可能なシーンコレクションを自動的に見つけることができます。 OBSでシーンコレクションを自動検索しますか?\n\nこれは後で設定 > 一般 > インポーターで変更できます。" Restart="再起動" diff --git a/UI/data/locale/ka-GE.ini b/UI/data/locale/ka-GE.ini index 5d39c03..cbed834 100644 --- a/UI/data/locale/ka-GE.ini +++ b/UI/data/locale/ka-GE.ini @@ -93,6 +93,7 @@ LockVolume="ხმის ჩაკეტვა" LogViewer="აღრიცხვის მნახველი" ShowOnStartup="ჩვენება გაშვებისას" OpenFile="ფაილის გახსნა" +AddValue="დაემატოს %1" AlreadyRunning.Title="OBS უკვე გაშვებულია" AlreadyRunning.Text="OBS უკვე გაშვებულია! გთხოვთ, ჯერ დახუროთ OBS-ის ყველა გაშვებული პროცესი, სანამ ახლის გაშვებას შეეცდებით. თუ მითითებული გაქვთ, რომ დახურვის ნაცვლად, OBS სისტემურ არეში უნდა ჩაიკეცოს, გთხოვთ მანდაც გადაამოწმოთ, დარჩენილი ხომ არაა." @@ -160,6 +161,7 @@ Basic.AutoConfig.StreamPage.DisconnectAccount="ანგარიშიდან Basic.AutoConfig.StreamPage.DisconnectAccount.Confirm.Title="გსურთ ანგარიშიდან გამოერთება?" Basic.AutoConfig.StreamPage.DisconnectAccount.Confirm.Text="ცვლილება დაუყოვნებლივ აისახება. ნამდვილად გსურთ, ანგარიშიდან გამოერთება?" Basic.AutoConfig.StreamPage.GetStreamKey="ნაკადის გასაღების მიღება" +Basic.AutoConfig.StreamPage.MoreInfo="ვრცლად" Basic.AutoConfig.StreamPage.UseStreamKey="ნაკადის გასაღების გამოყენება" Basic.AutoConfig.StreamPage.Service="მომსახურება" Basic.AutoConfig.StreamPage.Service.ShowAll="ყველას ჩვენება..." @@ -364,8 +366,8 @@ Deinterlacing.Yadif2x="Yadif 2x" Deinterlacing.TopFieldFirst="ზედა ველიდან" Deinterlacing.BottomFieldFirst="ქვედა ველიდან" -VolControl.SliderUnmuted="ხმის სამართავი „%1“: %2" -VolControl.SliderMuted="ხმის სამართავი „%1“: %2 (ამჟამად დადუმებული)" +VolControl.SliderUnmuted="ხმის სამართავი „%1“:" +VolControl.SliderMuted="ხმის სამართავი „%1“: (ამჟამად დადუმებული)" VolControl.Mute="'%1' დადუმება" VolControl.Properties="„%1“ – პარამეტრები" @@ -381,6 +383,7 @@ Basic.Main.RenameSceneCollection.Title="სცენის კრებული AddProfile.Title="პროფილის დამატება" AddProfile.Text="გთხოვთ, მიუთითოთ პროფილის დასახელება" +AddProfile.WizardCheckbox="თვითგამართვის მეგზურის ჩვენება" RenameProfile.Title="პროფილის გადარქმევა" @@ -395,6 +398,11 @@ Basic.SourceSelect.CreateNew="ახლის შექმნა" Basic.SourceSelect.AddExisting="არსებულის დამატება" Basic.SourceSelect.AddVisible="წყაროს გამოჩენა" +Basic.Main.Sources.Visibility="ხილვადობა" +Basic.Main.Sources.VisibilityDescription="განსაზღვრავს, ხილული იქნება თუ არა „%1“ საერთო ფონზე" +Basic.Main.Sources.Lock="ჩაკეტვა" +Basic.Main.Sources.LockDescription="„%1“ არ შეიცვლის ზომასა და მდებარეობას საერთო ფონზე" + Basic.PropertiesWindow="„%1“ – პარამეტრები" Basic.PropertiesWindow.AutoSelectFormat="%1 (თვითშერჩევა: %2)" Basic.PropertiesWindow.SelectColor="ფერის შერჩევა" @@ -634,13 +642,19 @@ Basic.Settings.Stream.StreamSettingsWarning="პარამეტრები Basic.Settings.Stream.MissingUrlAndApiKey="URL და ნაკადის გასაღები, ვერ მოიძებნა.\n\nგახსენით პარამეტრები და მიუთითეთ URL შესაბამისი გასაღებით „ნაკადის“ განყოფილებაში." Basic.Settings.Stream.MissingUrl="ნაკადის URL ვერ მოიძებნა.\n\nგახსენით პარამეტრები და მიუთითეთ URL „ნაკადის“ განყოფილებაში." Basic.Settings.Stream.MissingStreamKey="ნაკადის გასაღები ვერ მოიძებნა.\n\nგახსენით პარამეტრები და მიუთითეთ გასაღები „ნაკადის“ განყოფილებაში." +Basic.Settings.Stream.IgnoreRecommended="ნაკადის მომსახურების შემოთავაზებული პარამეტრების უგულებელყოფა" +Basic.Settings.Stream.IgnoreRecommended.Warn.Title="შემოთავაზებული პარამეტრების ჩანაცვლება" +Basic.Settings.Stream.IgnoreRecommended.Warn.Text="გაფრთხილება: მომსახურების ზღვრების უგულებელყოფამ, შესაძლოა გააფუჭოს ნაკადის ხარისხი ან არ მოგცეთ ეთერში გაშვების საშუალება.\n\nგანაგრძობთ?" +Basic.Settings.Stream.Recommended.MaxVideoBitrate="ვიდეოს უმაღლესი ბიტური სიხშირე: %1 კბწმ" +Basic.Settings.Stream.Recommended.MaxAudioBitrate="ხმის უმაღლესი ბიტური სიხშირე: %1 კბწმ" +Basic.Settings.Stream.Recommended.MaxResolution="დასაშვები გაფართოება: %1" +Basic.Settings.Stream.Recommended.MaxFPS="დასაშვები FPS: %1" 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.DynamicBitrate="ბიტური სიხშირის ცვალებადობა, ქსელის გადატვირთულობის ასარიდებლად" Basic.Settings.Output.DynamicBitrate.Beta="ბიტური სიხშირის ცვალებადობა, ქსელის გადატვირთულობის ასარიდებლად (საცდელი)" Basic.Settings.Output.DynamicBitrate.TT="ქსელის გადატვირთულობის შესამცირებლად კადრების გამოტოვების ნაცვლად, მიმდინარე ბიტური სიხშირის ცვალებადობა.\n\nგაითვალისწინეთ, რომ შედეგად შესაძლოა გაიზარდოს დაყოვნება მაყურებლებისთვის, დატვირთვის უეცარი მატებისას.\nბიტური სიხშირის ვარდნის შემდეგ, აღდგენა რამდენიმე წუთს გასტანს.\n\nამჟამად მხარდაჭერილია მხოლოდ RTMP." @@ -661,8 +675,8 @@ 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.VideoBitrate="გაფრთხილება: ნაკადის ვიდეოს სიხშირედ მიეთითება %1, რომელიც მოცემული მომსახურების უმაღლესი ზღვრული მნიშვნელობაა." +Basic.Settings.Output.Simple.Warn.AudioBitrate="გაფრთხილება: ნაკადის ხმის სიხშირედ მიეთითება %1, რომელიც მოცემული მომსახურების უმაღლესი ზღვრული მნიშვნელობაა." Basic.Settings.Output.Simple.Warn.CannotPause="შენიშვნა: ჩაწერის შეჩერება შეუძლებელია, თუ ჩაწერის ხარისხად მითითებულია „გაშვებული ნაკადის შესაბამისი“." Basic.Settings.Output.Simple.Warn.Encoder="გაფრთხილება: გაშვებული ნაკადისგან განსხვავებულ ხარისხში ჩანაწერის დაშიფვრა, ზრდის პროცესორის დატვირთვას, როცა ნაკადის გაშვება და ჩაწერა, ერთდროულად მიმდინარეობს." Basic.Settings.Output.Simple.Warn.Lossless="გაფრთხილება: უდანაკარგო ხარისხის მითითების შემთხვევაში, შეიქმნება მეტისმეტად დიდი ზომის ფაილები! უდანაკარგო ხარისხის ვიდეოს თითოეული წუთის მოცულობამ დისკზე, შესაძლოა 7 გიგაბაიტს გადააჭარბოს, მაღალი გარჩევადობისა და კადრის სიხშირის პირობებში. ხანგრძლივი ჩანაწერებისთვის, უდანაკარგოს არჩევა არაა მიზანშეწონილი, თუ არ გაქვთ საკმარისად დიდი მოცულობის თავისუფალი ადგილი დისკზე." @@ -673,6 +687,11 @@ Basic.Settings.Output.Simple.Encoder.Hardware.QSV="აპარატურუ Basic.Settings.Output.Simple.Encoder.Hardware.AMD="აპარატურული (AMD)" Basic.Settings.Output.Simple.Encoder.Hardware.NVENC="აპარატურული (NVENC)" Basic.Settings.Output.Simple.Encoder.SoftwareLowCPU="პროგრამული (x264 პროცესორის დაბალი მოხმარების მზა პარამეტრები, ზრდის ფაილის ზომას)" +Basic.Settings.Output.Simple.TwitchVodTrack="Twitch-VOD-ჩანაწერი (გამოიყენება ბილიკი 2)" +Basic.Settings.Output.Warn.EnforceResolutionFPS.Title="არათავსებადი გაფართოება/კადრის სიხშირე" +Basic.Settings.Output.Warn.EnforceResolutionFPS.Msg="ნაკადის გაშვების ამ მომსახურებაზე, მითითებული გამოტანის გაფართოება და/ან კადრის სიხშირე არაა მხარდაჭერილი. შეცვლიან უახლოესი თავსებადი მნიშვნელობით:\n\n%1\n\nგსურთ, განაგრძოთ?" +Basic.Settings.Output.Warn.EnforceResolutionFPS.Resolution="გაფართოება: %1" +Basic.Settings.Output.Warn.EnforceResolutionFPS.FPS="FPS (კადრი/წმ): %1" Basic.Settings.Output.VideoBitrate="ვიდეოს ბიტური სიხშირე" Basic.Settings.Output.AudioBitrate="ხმის ბიტური სიხშირე" Basic.Settings.Output.Reconnect="ხელახლა დაკავშირება ავტომატურად" @@ -687,15 +706,16 @@ 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.Audio.Track5="ბილიკი 5" Basic.Settings.Output.Adv.Audio.Track6="ბილიკი 6" +Basic.Settings.Output.Adv.TwitchVodTrack="Twitch-VOD-ჩანაწერი" Basic.Settings.Output.Adv.Recording="ჩაწერა" +Basic.Settings.Output.Adv.Recording.RecType="ჩანაწერის სახეობა" Basic.Settings.Output.Adv.Recording.Type="სახეობა" Basic.Settings.Output.Adv.Recording.Type.Standard="ჩვეულებრივი" Basic.Settings.Output.Adv.Recording.Type.FFmpegOutput="მითითებული გამოტანა (FFmpeg)" @@ -753,9 +773,9 @@ 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="Lanczos (მკვეთრი მასშტაბირება, 36 შერჩევა)" -Basic.Settings.Video.DownscaleFilter.Area="სივრცე (შეწონილი ჯამი, 4/6/9 შერჩევა)" +Basic.Settings.Video.DownscaleFilter.Bicubic="ბიკუბური (მკვეთრი მასშტაბირება, 16 დაყოფა)" +Basic.Settings.Video.DownscaleFilter.Lanczos="Lanczos (მკვეთრი მასშტაბირება, 36 დაყოფა)" +Basic.Settings.Video.DownscaleFilter.Area="სივრცე (შეწონილი ჯამი, 4/6/9 დაყოფა)" Basic.Settings.Audio="ხმა" Basic.Settings.Audio.SampleRate="სიხშირე" @@ -823,13 +843,18 @@ Basic.AdvAudio="ხმის გაფართოებული პარა Basic.AdvAudio.ActiveOnly="მხოლოდ მოქმედი წყაროები" Basic.AdvAudio.Name="სახელი" Basic.AdvAudio.Volume="ხმის დონე" +Basic.AdvAudio.VolumeSource="ხმოვანება „%1“" Basic.AdvAudio.Mono="მონო" +Basic.AdvAudio.MonoSource="ხმის დაყვანა მონოზე „%1“" Basic.AdvAudio.Balance="წონასწორობა" +Basic.AdvAudio.BalanceSource="წონასწორობა „%1“" Basic.AdvAudio.SyncOffset="სინქრონიზაციის გასწორება" +Basic.AdvAudio.SyncOffsetSource="სინქრონიზაციის გასწორება „%1“" Basic.AdvAudio.Monitoring="ხმის მოსმენა" Basic.AdvAudio.Monitoring.None="მოსმენის გარეშე" Basic.AdvAudio.Monitoring.MonitorOnly="მხოლოდ მოსმენა (უხმო გამოტანა)" Basic.AdvAudio.Monitoring.Both="მოსმენა და გამოტანა" +Basic.AdvAudio.MonitoringSource="ხმის მოსასმენი „%1“" Basic.AdvAudio.AudioTracks="ბილიკები" Basic.Settings.Hotkeys="ღილაკები" diff --git a/UI/data/locale/kab-KAB.ini b/UI/data/locale/kab-KAB.ini new file mode 100644 index 0000000..593120f --- /dev/null +++ b/UI/data/locale/kab-KAB.ini @@ -0,0 +1,804 @@ + +Language="Taglizit" + +OK="Ih" +Apply="Snes" +Cancel="Sefsex" +Close="Mdel" +Save="Sekles" +Discard="Sefsex" +Disable="Sens" +Yes="Ih" +No="Ala" +Add="Rnu" +Remove="Kkes" +Rename="Snifel isem" +Interact="Tamyigawt" +Filters="Imzizdigen" +Properties="Iraten" +MoveUp="Smutti d asawen" +MoveDown="Smutti d akessar" +Settings="Iɣewwaren" +Display="Beqqeḍ" +Name="Isem" +Exit="Ffeɣ" +Mixer="Asexlaḍ n umeslaw" +Browse="Snirem" +Stereo="Stiryu" +StudioProgramProjector="Amagar s ugdil aččuran (ahil)" +PreviewProjector="Amagar s ugdil aččuran (tadlayt)" +SceneProjector="Amagar s ugdil aččuran (asayes)" +SourceProjector="Amagar s ugdil aččuran (aɣbalu)" +StudioProgramWindow="Amagar s usfaylu (ahil)" +PreviewWindow="Amagar s usfaylu (tadlayt)" +SceneWindow="Amagar s usfaylu (aɣbalu)" +SourceWindow="Amagar s usfaylu (aɣbalu)" +MultiviewProjector="Aṭas n tmuɣliwin (agdil aččuran)" +MultiviewWindowed="Aṭas n tmuɣliwin (s usfaylu)" +ResizeProjectorWindowToContent="Sezg asfaylu ɣer ugbur" +Clear="Sfeḍ" +Revert="Err-d" +Show="Sken" +Hide="Ffer" +UnhideAll="Sban-d kulec" +Untitled="War azwel" +New="Amaynut" +Duplicate="Sisleg" +Enable="Sermed" +DisableOSXVSync="Sens macOS V-Sync" +ResetOSXVSyncOnExit="Ales awennez n macOS V-Sync mi ara teffeɣeḍ" +Transition="Asaka" +QuickTransitions="Isuka iruraden" +FadeToBlack="Tifsit ɣer uberkan" +Left="Azelmaḍ" +Right="Ayfus" +Top="Ukessawen" +Bottom="Uksar" +Reset="Ales awennez" +Hours="Isragen" +Minutes="Tisdatin" +Seconds="Tasinin" +Deprecated="D aqbur" +ReplayBuffer="Tallunt n weḥraz n tulsa n tɣuri" +Import="Kter" +Export="Sifeḍ" +Copy="Nɣel" +Paste="Senṭeḍ" +PasteReference="Senṭeḍ (tamselɣut)" +PasteDuplicate="Senṭeḍ (Sisleg)" +RemuxRecordings="Selket ikalasen" +Next="Win ɣers" +Back="Tuɣalin" +Defaults="Amezwar" +HideMixer="Ffer deg usexlaḍ" +TransitionOverride="Ḥettem asaka" +None="Ulac" +StudioMode.Preview="Tadlayt" +StudioMode.Program="Ahil" +ShowInMultiview="Beqqeḍ di tmuɣli tusgitt" +VerticalLayout="Taneɣruft tubdidt" +Group="Agraw" +DoNotShowAgain="Ur d-sskan ara tikelt-nniḍen" +Default="(Amezwar)" +Calculating="Asiḍen..." +Fullscreen="Agdil aččuran" +Windowed="S usfaylu" +Percent="Afmiḍi" +RefreshBrowser="Sismeḍ" +AspectRatio="Assaɣ n tmeẓri %1:%2" +LockVolume="Sekkeṛ ableɣ" +LogViewer="Wali aɣmmis" +ShowOnStartup="Sken di tnekra" +OpenFile="Ldi afaylu" +AddValue="Rnu %1" + +AlreadyRunning.Title="OBS itteddu yakan" +AlreadyRunning.Text="OBS itteddu yakan! Ma yella ur teɛmideḍ ara i waya, ttxil-k msens kra n tummanin n OBS send ad tɛerḍeḍ ad tsekkereḍ tummant tamaynutt. Ma tesɛiḍ OBS yettusɣewren ɣer talɣa taddayt di teɣzut n telɣa, ttxil-k m selken ma yella itteddu dina." +AlreadyRunning.LaunchAnyway="Sekker akken yebɣu yili" + +ChromeOS.Title="Tiɣerɣert ur nettwadhel ara" +ChromeOS.Text="OBS yettban-d am wakken itteddu deg unagbar n ChromeOS. Tiɣerɣert-agi ur tettwadhel ara" + + + +Auth.Authing.Title="Asesteb..." +Auth.Authing.Text="Asesteb s %1, ma ulac uɣilif arǧu..." +Auth.AuthFailure.Title="Tuccḍa n usesteb" +Auth.AuthFailure.Text="Asesteb s %1:\n\n%2: %3 ur yeddi ara" +Auth.InvalidScope.Title="Yettwasra usesteb" +Auth.InvalidScope.Text="Israyen n wesesteb i %1 beddelen. Kra n twuriwin izmer ur wjident ara." +Auth.LoadingChannel.Title="Asader n telɣut n ubadu..." +Auth.LoadingChannel.Text="Asader n telɣut n ubadu i %1, ma ulac uɣilif arǧu..." +Auth.ChannelFailure.Title="Asali n ubadu ur yeddi ara" +Auth.ChannelFailure.Text="Asali n telɣut n ubadu i %1\n\n%2: %3 ur yeddi ara" +Auth.Chat="Ameslay" +Auth.StreamInfo="Talɣut n usuddem" +TwitchAuth.Stats="Tiddadanin n Twitch" +TwitchAuth.Feed="Asuddem n wermud Twitch" +TwitchAuth.TwoFactorFail.Title="Ulamek asuter n tsarut n usuddem" +TwitchAuth.TwoFactorFail.Text="OBS igguma ad iqqen ɣer umiḍan-inek n Twitch. Ma ulac uɣilif, tḥeqqeq belli asesteb s snat n tarrayin yettusbadu deg yiɣewwaren n tɣellist n Twitchacku ayagi ilaq i usekker n usuddem." +RestreamAuth.Channels="Ibuda n Restream" + +Copy.Filters="Nɣel imzizdgen" +Paste.Filters="Senṭeḍ imzizdgen" + +BrowserPanelInit.Title="Tulsa n uwennez n yiminig..." +BrowserPanelInit.Text="Tulsa n uwennez n yiminig, ma ulac uɣilif arǧu..." + +BandwidthTest.Region="Tamnaḍt" +BandwidthTest.Region.US="Iwanaken yeddukklen" +BandwidthTest.Region.EU="Turuft" +BandwidthTest.Region.Asia="Asya" +BandwidthTest.Region.Other="Wayeḍ" + +Basic.AutoConfig="Amallal n uswel awurman" +Basic.AutoConfig.ApplySettings="Snes iɣewwaren" +Basic.AutoConfig.StartPage="Talɣut n useqdec" +Basic.AutoConfig.StartPage.SubTitle="Ini-d acu iwumi ara tesqedceḍ ahil" +Basic.AutoConfig.StartPage.PrioritizeStreaming="Sekk i usuddem, asekles d asnaw" +Basic.AutoConfig.StartPage.PrioritizeRecording="Sekk kan i usekles, ulac asuddem" +Basic.AutoConfig.StartPage.PrioritizeVirtualCam="Ad sqedceɣ kan takamiṛat tuhlist" +Basic.AutoConfig.VideoPage="Iɣewwaren n uvidyu" +Basic.AutoConfig.VideoPage.SubTitle="Fk-d iɣewwaren n uvidyu i tebɣiḍ ad tesqedceḍ" +Basic.AutoConfig.VideoPage.BaseResolution.UseCurrent="Seqdec (%1x%2) amiran" +Basic.AutoConfig.VideoPage.BaseResolution.Display="Abeqqeḍ %1 (%2x%3)" +Basic.AutoConfig.VideoPage.FPS.UseCurrent="Seqdec (%1) amiran" +Basic.AutoConfig.VideoPage.FPS.PreferHighFPS="Ama 60 ama 30, maca smenyif 60 ma yella wamek" +Basic.AutoConfig.VideoPage.FPS.PreferHighRes="Ama 60 ama 30, maca smenyif tabadut tafellayt" +Basic.AutoConfig.StreamPage="Talɣut n usuddem" +Basic.AutoConfig.StreamPage.SubTitle="Ma ulac uɣilif, sekcem talɣut n usuddem-inek m" +Basic.AutoConfig.StreamPage.ConnectAccount="Qqen amiḍan (yettwasemter)" +Basic.AutoConfig.StreamPage.DisconnectAccount="Senser amiḍan" +Basic.AutoConfig.StreamPage.DisconnectAccount.Confirm.Title="Senser amiḍan?" +Basic.AutoConfig.StreamPage.DisconnectAccount.Confirm.Text="Abeddel-agi ad ittusnes tura kan. D tidet tebɣiḍ ad tsensreḍ amiḍan-inek m?" +Basic.AutoConfig.StreamPage.GetStreamKey="Awi-d tasarut n usuddem" +Basic.AutoConfig.StreamPage.MoreInfo="Ugar n telɣut" +Basic.AutoConfig.StreamPage.UseStreamKey="Seqdec tasarut n usuddem" +Basic.AutoConfig.StreamPage.Service="Ameẓlu" +Basic.AutoConfig.StreamPage.Service.ShowAll="Sken akk..." +Basic.AutoConfig.StreamPage.Service.Custom="Yugen..." +Basic.AutoConfig.StreamPage.Server="Aqeddac" +Basic.AutoConfig.StreamPage.StreamKey="Tasarut n usuddem" +Basic.AutoConfig.StreamPage.StreamKey.LinkToSite="(Aseɣwen)" +Basic.AutoConfig.StreamPage.PreferHardwareEncoding="Smenyif asettengel n warrum" +Basic.AutoConfig.StreamPage.StreamWarning.Title="Alɣu n usuddem" +Basic.AutoConfig.TestPage="Igmaḍ n taggara" +Basic.AutoConfig.TestPage.SubTitle.Complete="Akayad yemmed" +Basic.AutoConfig.TestPage.TestingBandwidth.Connecting="Ala yetteqqen ɣer: %1..." +Basic.AutoConfig.TestPage.TestingBandwidth.ConnectFailed="Igguma ad iqqen ɣer uqeddac, ma ulac uɣilif selken tuqqna-inek m ɣer internet sakin eɛreḍ tikkelt-nniḍen." +Basic.AutoConfig.TestPage.TestingBandwidth.Server="Asekyed n tehri n tesfift i: %1" +Basic.AutoConfig.TestPage.TestingStreamEncoder="Asekyed n usettengal n usuddem, ayagi yezmer ad yeṭṭef tasdidt..." +Basic.AutoConfig.TestPage.TestingRecordingEncoder="Asekyed n usettengal n usekles, ayagi yezmer ad yeṭṭef tasdidt..." +Basic.AutoConfig.TestPage.TestingRes="Asekyed n tbdadutin, ayagi yezmer ad yeṭṭef kra n tesdidin..." +Basic.AutoConfig.TestPage.TestingRes.Fail="Asekker n usettengal ur yeddi ara" +Basic.AutoConfig.TestPage.TestingRes.Resolution="Asekyed n %1x%2 %3 FPS..." +Basic.AutoConfig.TestPage.Result.StreamingEncoder="Asettengal n usuddem" +Basic.AutoConfig.TestPage.Result.RecordingEncoder="Asettengal n usekles" +Basic.AutoConfig.RunAnytime="Ayagi yezmer ad yettwaselekm melmi tebɣiḍ ma teddiḍ ɣer wumuɣ Ifecka." + +Basic.Stats="Tiddadanin" +Basic.Stats.CPUUsage="Aseqdec n CPU" +Basic.Stats.HDDSpaceAvailable="Tallunt n uḍebsi iwejden" +Basic.Stats.MemoryUsage="Aseqdec n tkatut" +Basic.Stats.Output.Stream="Asuddem" +Basic.Stats.Output.Recording="Asekles" +Basic.Stats.Status="Addad" +Basic.Stats.Status.Recording="Asekles" +Basic.Stats.Status.Live="Srid" +Basic.Stats.Status.Reconnecting="Tulsa n tuqqna" +Basic.Stats.Status.Inactive="Yensa" +Basic.Stats.Status.Active="Yermed" +Basic.Stats.DroppedFrames="Ikataren iṛuḥen (azeḍḍa)" +Basic.Stats.MegabytesSent="Aɣrud n yisefka n tuffɣa" +Basic.Stats.Bitrate="Aktum" +Basic.Stats.DiskFullIn="Aḍebsi ad yaččar di (tasmekta n)" +Basic.Stats.ResetStats="Ales awennez n tddadanin" + +ResetUIWarning.Title="D tidet tebɣiḍ ad talseḍ awennez n ugrudem n useqdac?" + +Updater.Title="Yewjed lqem amaynut" +Updater.Text="Yella lqem amaynut iwejden:" +Updater.UpdateNow="Leqqem Tura" +Updater.RemindMeLater="Smekti-yi-d areḍqal" +Updater.Skip="Ttu lqem" +Updater.Running.Title="Ahil itteddu akka tura" +Updater.Running.Text="Llant tuffɣiwin turmidin akka tura, ma ulac uɣilif sens kra tuffɣiwin turmidin send ad tɛerḍeḍ ad tleqqemeḍ" +Updater.NoUpdatesAvailable.Title="Ulac ileqman iwejden" +Updater.NoUpdatesAvailable.Text="Ulac ileqman iwejden akka tura" +Updater.FailedToLaunch="Ulamek asekker n uleqqem" +Updater.GameCaptureActive.Title="Tuṭṭfa n wurar termed" +Updater.GameCaptureActive.Text="Tamkarḍit n tuṭṭfa n wuraren « hook » tettwaseqdac akka tura. Ma ulac uɣilif sens kra n wuraren/wahilen i yettwaṭṭafen akka tura (neɣ ales asekker n Windows) sakin eɛreḍ tikkelt-nniḍen." + +QuickTransitions.DuplicateScene="Sisleg asayes" +QuickTransitions.EditProperties="Sisleg iɣbula" +QuickTransitions.HotkeyName="Asaka arurad: %1" + +Basic.TransitionProperties="Iraten n usaka" +Basic.SceneTransitions="Asaka n yisuyas" +Basic.TransitionDuration="Tanzagt" +Basic.TogglePreviewProgramMode="Askar n ustudyu" + +TransitionNameDlg.Text="Ma ulac uɣilif sekcem isem i usayes" +TransitionNameDlg.Title="Isem n usaka" + +TitleBar.Profile="Amaɣnu" +TitleBar.Scenes="Isuyas" + +NameExists.Title="Isem-agi yella yakan" +NameExists.Text="Isem-agi yettwaseqdec yakan." + +NoNameEntered.Title="Ma ulac uɣilif, sekcem isem ameɣtu" +NoNameEntered.Text="Ur tezmireḍ ara ad tesqedceḍ ismawen ilmawen." + +ConfirmStart.Title="Ad tebduḍ asuddem?" +ConfirmStart.Text="D tidet tebɣiḍ ad tebduḍ asuddem?" + +ConfirmStop.Title="Ad tḥebseḍ asuddem?" +ConfirmStop.Text="D tidet tebɣiḍ ad tḥebseḍ asuddem?" + +ConfirmStopRecord.Title="Ad tḥebseḍ asekles?" +ConfirmStopRecord.Text="D tidet tebɣiḍ ad tḥebseḍ asekles?" + +ConfirmBWTest.Title="Sekker akayad n tehri n tesfift?" + +ConfirmExit.Title="Ad teffɣeḍ si OBS?" +ConfirmExit.Text="OBS itteddu akka tura. Akk isuddman/ikalasen ad xsin. D tidet tebɣiḍ ad teffɣeḍ?" + +ConfirmRemove.Title="Sentem tukksa" +ConfirmRemove.Text="D tidet tebɣiḍ ad tekkseḍ '$1'?" +ConfirmRemove.TextMultiple="D tidet tebɣiḍ ad tekkseḍ %1 n yiferdisen?" + +Output.StartStreamFailed="D awezɣi asekker n usuddem" +Output.StartRecordingFailed="D awezɣi asekker n usekles" +Output.StartReplayFailed="Ulamek asekker n tallunt nweḥraz n tulsa n tɣuri" + + +Output.ConnectFail.Title="Ulamek tuqqna" +Output.ConnectFail.BadPath="Abrid neɣ URL n tuqqna d armeɣtu. Ma ulac uɣilif selken iɣewwaren-inek m akken ad tsentmeḍ belli d imeɣta." +Output.ConnectFail.ConnectFailed="D awezɣi tuqqna s aqedac" +Output.ConnectFail.InvalidStream="D awezɣi adduf ɣer ubadu neɣ ɣer tsarut n usuddem, ma ulac uɣilif selken tasarut n usuddem-inek m. Ma d tameɣtut, yezmer ad yili wugur di tuqqna s aqeddac." +Output.ConnectFail.Error="Teḍra-d tuccḍa ur netturaǧu ara mi neɛreḍ ad nqqen s aqeddac. Ugar n telɣut deg ufaylu n uɣmis." +Output.ConnectFail.Disconnected="Yenser seg uqeddac." + +Output.StreamEncodeError.Title="Tuccḍa n usettengel" +Output.StreamEncodeError.Msg="Asettengal yemlal-d tuccḍa deg usuddem." + +Output.RecordFail.Title="D awezɣi asekker n usekles" +Output.RecordFail.Unsupported="Amasal n tuffɣa ur yettwadhel ara neɣ ur yedhil ara ugar n yiwet n tezribt tameslawt. Ma ulac uɣilif selken iɣewwaren-ik m sakin eɛreḍ tikkelt-nniḍen." +Output.RecordNoSpace.Title="Ulac ddeqs n tallunt n uḍebsi" +Output.RecordNoSpace.Msg="Ulac ddeqs n tallunt n uḍebsi akken ad ikemmel usekles." +Output.RecordError.Title="Tuccḍa n usekles" +Output.RecordError.Msg="Teḍra-d tucḍa deg usekles." +Output.RecordError.EncodeErrorMsg="Asettengal yemlal-d tuccḍa deg usekles." + +Output.BadPath.Title="Yir abrid n ufaylu" +Output.BadPath.Text="Abrid ittusɣewren i ufaylu n tuffɣa d armeɣtu. Ma ulac uɣilif selken iɣewwaren-inek m akken ad tsentmeḍ belli yettuseɣwer ubrd n ufaylu ameɣtu." + +LogReturnDialog="Asili n uɣmis yedda akken iwata" +LogReturnDialog.Description="Afaylu n uɣmis yuli. Tura tzemreḍ ad tebḍuḍ tansa URL i weseɣti neɣ i tedhelt." +LogReturnDialog.Description.Crash="Aneqqis n uɣelluy yuli. Tura tzemreḍ ad tebḍuḍ tansa URL i weseɣti neɣ i tedhelt." +LogReturnDialog.CopyURL="Nɣel URL" +LogReturnDialog.AnalyzeURL="Sleḍ" +LogReturnDialog.ErrorUploadingLog="Tuccḍa deg usali n ufaylu n uɣmis" + +Remux.SourceFile="Asekles n OBS" +Remux.TargetFile="Afaylu anican" +Remux.Remux="Selket" +Remux.Stop="Ḥebes aselket" +Remux.ClearFinished="Sfeḍ iferdisen ifukken" +Remux.ClearAll="Sfeḍ akk iferdisen" +Remux.OBSRecording="Asekles n OBS" +Remux.SelectRecording="Fren asekles n OBS..." +Remux.SelectTarget="Fren afaylu anican..." +Remux.FileExistsTitle="Afaylu anican yella" +Remux.FileExists="Ifuyla-agi inicanen llan yakan. Tebɣiḍ ad ten-tsemselsiḍ?" +Remux.HelpText="Sers ifuyla deg usfaylu-agi akken ad ten-tselkteḍ, neɣ fren tabniqt \"Asekles OBS\" akken ad tnadiḍ afaylu." + +UpdateAvailable="Yewjed lqem amaynut" +UpdateAvailable.Text="Lqem %1.%2.%3 yewjed tura. Ssit dagi akken ad t-tsidreḍ" + +Basic.DesktopDevice1="Ameslaw n tnarit" +Basic.DesktopDevice2="Ameslaw n tnarit 2" + +Basic.Scene="Asayes" +Basic.DisplayCapture="Tuṭṭfa n ubeqqeḍ" + +Basic.Main.PreviewConextMenu.Enable="Sermed tadlayt" + +Basic.Main.Preview.Disable="Sens tadlayt" + +ScaleFiltering.Point="Tanqiḍt" +ScaleFiltering.Area="Taɣzut" + +Deinterlacing.Linear="Imzireg" +Deinterlacing.Linear2x="Imzireg 2x" +Deinterlacing.Yadif="Yadif" +Deinterlacing.Yadif2x="Yadif 2x" +Deinterlacing.TopFieldFirst="Urti n ufella d amezwaru" + +VolControl.SliderUnmuted="Taḥnaccaḍt n ubleɣ i '%1':" +VolControl.SliderMuted="Taḥnaccaḍt n ubleɣ i '%1': (akka tura yessusem)" +VolControl.Mute="'%1' d asusam" +VolControl.Properties="Iraten i '%1'" + +Basic.Main.AddSceneDlg.Title="Rnu asayes" +Basic.Main.AddSceneDlg.Text="Sekcem isem n usayes" + +Basic.Main.DefaultSceneName.Text="Asayes %1" + +Basic.Main.AddSceneCollection.Title="Rnu talkensit n yisuyas" +Basic.Main.AddSceneCollection.Text="Ma ulac uɣilif sekcem isem i telkensit n yisuyas" + +Basic.Main.RenameSceneCollection.Title="Snifel isem n telkensit n yisuyas" + +AddProfile.Title="Rnu amaɣnu" +AddProfile.Text="Ma ulac uɣilif sekcem isem i umaɣnu" +AddProfile.WizardCheckbox="Sken amallal n uswel awurman" + +RenameProfile.Title="Snifel isem n umaɣnu" + +Basic.Main.MixerRename.Title="Snifel isem n uɣbalu ameslaw" +Basic.Main.MixerRename.Text="Ma ulac uɣilif sekcem isem i uɣbalu ameslaw" + + +Basic.Main.PreviewDisabled="Tadlayt tensa akka tura" + +Basic.SourceSelect="Snulfu-d/fren aɣbalu" +Basic.SourceSelect.CreateNew="Snulfu-d amaynut" +Basic.SourceSelect.AddExisting="Rnu aɣbalu yellan" +Basic.SourceSelect.AddVisible="Err aɣbalu ad yettban" + +Basic.Main.Sources.Visibility="Tawalit" +Basic.Main.Sources.VisibilityDescription="Ad isenqed tawalit n '%1' di teɣzut n usuneɣ" +Basic.Main.Sources.Lock="Sekkeṛ" + +Basic.PropertiesWindow="Iraten i '%1'" +Basic.PropertiesWindow.AutoSelectFormat="%1 (tafrayt tawurmant: %2)" +Basic.PropertiesWindow.SelectColor="Fren ini" +Basic.PropertiesWindow.SelectFont="Fren tasefsit" +Basic.PropertiesWindow.ConfirmTitle="Iɣewwaren ttwabeddelen" +Basic.PropertiesWindow.Confirm="Llan yibeddilen ur yettwaskelsen ara. Tebɣiḍ ad ten-teskelseḍ?" +Basic.PropertiesWindow.NoProperties="Ulac iraten iwejden" +Basic.PropertiesWindow.AddFiles="Rnu ifuyla" +Basic.PropertiesWindow.AddDir="Rnu akaram" +Basic.PropertiesWindow.AddURL="Rnu abrid/URL" +Basic.PropertiesWindow.AddEditableListDir="Rnu akaram ɣer '%1'" +Basic.PropertiesWindow.AddEditableListFiles="Rnu ifuyla ɣer '%1'" +Basic.PropertiesWindow.AddEditableListEntry="Rnu anekcum ɣer '%1'" +Basic.PropertiesWindow.EditEditableListEntry="Ẓreg anekcum si %1" + +Basic.PropertiesView.FPS.Simple="Azalen n FPS iḥerfiyen" +Basic.PropertiesView.FPS.ValidFPSRanges="Tigrummiwin FPS timeɣta:" + +Basic.InteractionWindow="Myeg akked '%1'" + +Basic.StatusBar.Reconnecting="Tegzem tuqqna, tulsa n tuqqna di %2 n tasinit (tasinin) (aneɛruḍ%1)" +Basic.StatusBar.AttemptingReconnect="Aneɛruḍ n tulsa n tuqqna...(aneɛruḍ %1)" +Basic.StatusBar.ReconnectSuccessful="Tulsa n tuqqna tedda akken iwata" +Basic.StatusBar.Delay="Asemmezger (%1 tasint)" +Basic.StatusBar.DelayStartingIn="Asemmezger (beddu di %1 tasint)" +Basic.StatusBar.DelayStoppingIn="Asemmezger (aḥbas di %1 tasint)" +Basic.StatusBar.DelayStartingStoppingIn="Asemmezger (aḥbas di %1 tasint, beddu di %2 tasint)" + +Basic.Filters="Imzizdigen" +Basic.Filters.AsyncFilters="Imzizedgen ameslaw/avidyu" +Basic.Filters.AudioFilters="Imzizedgen n umeslaw" +Basic.Filters.EffectFilters="Imzizedgen n usemdu" +Basic.Filters.Title="Imzizedgen i '%1'" +Basic.Filters.AddFilter.Title="Isem n umzizdeg" +Basic.Filters.AddFilter.Text="Ma ulac uɣilif sekcem isem i umzizdeg" + +Basic.TransformWindow="Abeddel n uferdis n usayes" +Basic.TransformWindow.Position="Ideg" +Basic.TransformWindow.Rotation="Tuzzya" +Basic.TransformWindow.Size="Tiddi" +Basic.TransformWindow.Crop="Ɣeẓ" + +Basic.TransformWindow.Alignment.TopLeft="Ukessawen s azelmaḍ" +Basic.TransformWindow.Alignment.TopCenter="Ukessawen di tlemmast" +Basic.TransformWindow.Alignment.TopRight="Uksawen s ayfus" +Basic.TransformWindow.Alignment.CenterLeft="Di tlemmast s azelmaḍ" +Basic.TransformWindow.Alignment.Center="Alemmas" +Basic.TransformWindow.Alignment.CenterRight="Di tlemmast s ayfus" +Basic.TransformWindow.Alignment.BottomLeft="Ukessar s azelmaḍ" +Basic.TransformWindow.Alignment.BottomCenter="Ukessar di tlemmast" +Basic.TransformWindow.Alignment.BottomRight="Ukessar s ayfus" + +Basic.TransformWindow.BoundsType.None="War azizdew" +Basic.TransformWindow.BoundsType.MaxOnly="Tiddi tafellayt kan" +Basic.TransformWindow.BoundsType.Stretch="Snejbad ɣer yiran" + +Basic.Main.AddSourceHelp.Title="Ulamek timerna n usayes" +Basic.Main.AddSourceHelp.Text="Isefk ad tesɛuḍ ma drus 1 n usayes akken ad ternuḍ aɣbalu." + +Basic.Main.Scenes="Isuyas" +Basic.Main.Sources="Iɣbula" +Basic.Main.Controls="Isenqaden" +Basic.Main.Connecting="Ala yetteqqen..." +Basic.Main.StartRecording="Bdu asekles" +Basic.Main.StartReplayBuffer="Sekker taɣuri n tallunt n weḥraz" +Basic.Main.SaveReplay="Sekles tulsa n tɣuri" +Basic.Main.StartStreaming="Bdu asuddem" +Basic.Main.StartVirtualCam="Sekker takamiṛat tuhlist" +Basic.Main.StopRecording="Ḥbes asekles" +Basic.Main.PauseRecording="Sbedd asekles" +Basic.Main.UnpauseRecording="Kemmel asekles" +Basic.Main.StoppingRecording="Aseḥbes n usekles..." +Basic.Main.StopReplayBuffer="Seḥbes taɣuri n tallunt n weḥraz" +Basic.Main.StoppingReplayBuffer="Aseḥbes taɣuri n tallunt n weḥraz..." +Basic.Main.StopStreaming="Ḥbes asuddem" +Basic.Main.StoppingStreaming="Aḥbas n usuddem..." +Basic.Main.ForceStopStreaming="Seḥbes asuddem (sefsex asemmezger)" +Basic.Main.ShowContextBar="Beqqeḍ afeggag n yifecka Iɣbula" +Basic.Main.HideContextBar="Ffer afeggag n yifecka Iɣbula" +Basic.Main.StopVirtualCam="Ḥbes takamirat tuhlist" +Basic.Main.Group="Agraw %1" +Basic.Main.GroupItems="Segrew iferdisen yettwafernen" +Basic.Main.Ungroup="Freq" +Basic.Main.GridMode="Askar n uferrug" +Basic.Main.ListMode="Askar n tebdart" + +Basic.MainMenu.File="Afaylu" +Basic.MainMenu.File.Export="Sifeḍ" +Basic.MainMenu.File.Import="Kter" +Basic.MainMenu.File.ShowRecordings="Beqqeḍ ikalasen" +Basic.MainMenu.File.Settings="Iɣewwaren" +Basic.MainMenu.File.ShowSettingsFolder="Beqqeḍ akaram n yiɣewwaren" +Basic.MainMenu.File.ShowProfileFolder="Beqqeḍ akaram n umaɣnu" +Basic.MainMenu.AlwaysOnTop="Yalas nnig" +Basic.MainMenu.File.Exit="Ffeɣ" + +Basic.MainMenu.Edit="Ẓreg" +Basic.MainMenu.Edit.Undo="Sefsex" +Basic.MainMenu.Edit.Redo="Err-d" +Basic.MainMenu.Edit.UndoAction="Sefsex $1" +Basic.MainMenu.Edit.RedoAction="Err-d $1" +Basic.MainMenu.Edit.LockPreview="Sekkeṛ tadlayt" +Basic.MainMenu.Edit.Scale.Window="Sezg ɣer usfaylu" +Basic.MainMenu.Edit.Scale.Canvas="Taɣzut n usuneɣ (%1x%2)" +Basic.MainMenu.Edit.Scale.Output="Tuffɣa (%1x%2)" +Basic.MainMenu.Edit.Transform="Selket" +Basic.MainMenu.Edit.Transform.EditTransform="Ẓreg aselket..." +Basic.MainMenu.Edit.Transform.CopyTransform="Nɣel aselket" +Basic.MainMenu.Edit.Transform.PasteTransform="Senṭeḍ aselket" +Basic.MainMenu.Edit.Transform.ResetTransform="Ales awennez n uselket" +Basic.MainMenu.Edit.Transform.Rotate90CW="Zzi s 90 n tfesniwin di tnila n temrilt" +Basic.MainMenu.Edit.Transform.Rotate90CCW="Zzi s 90 n tfesniwin mgal tamrilt" +Basic.MainMenu.Edit.Transform.Rotate180="Zzi s 180 n tfesniwin" +Basic.MainMenu.Edit.Transform.FlipHorizontal="Tuttya taglawant" +Basic.MainMenu.Edit.Transform.FlipVertical="Tuttya tubdidt" +Basic.MainMenu.Edit.Transform.FitToScreen="Sezg ɣer ugdil" +Basic.MainMenu.Edit.Transform.StretchToScreen="Snejbad ɣer ugdil" +Basic.MainMenu.Edit.Transform.CenterToScreen="Di tlemmast n wegdil" +Basic.MainMenu.Edit.Transform.VerticalCenter="Di tlemmast s ibeddi" +Basic.MainMenu.Edit.Transform.HorizontalCenter="Di tlemmast s uglawi" +Basic.MainMenu.Edit.Order="Amizzwer" +Basic.MainMenu.Edit.Order.MoveUp="Smutti d asawen" +Basic.MainMenu.Edit.Order.MoveDown="Smutti d akessar" +Basic.MainMenu.Edit.Order.MoveToTop="Smutti d asawen maḍi" +Basic.MainMenu.Edit.Order.MoveToBottom="Smutti d akessar" +Basic.MainMenu.Edit.AdvAudio="Iraten inaẓiyen n uvidyu" + +Basic.MainMenu.View="Tamuɣli" +Basic.MainMenu.View.Toolbars="Afeggag n yifecka" +Basic.MainMenu.View.Docks.ResetUI="Ales awennez n ugrudem n useqdac" +Basic.MainMenu.View.Docks.LockUI="Sekkeṛ agrudem n useqdac" +Basic.MainMenu.View.ListboxToolbars="Tiqeffalin n tebdart Asayes/Aɣbalu" +Basic.MainMenu.View.ContextBar="Afeggag n yifecka Iɣbula" +Basic.MainMenu.View.SceneTransitions="Asaka n yisuyas" +Basic.MainMenu.View.SourceIcons="Tignitin n uɣbalu" +Basic.MainMenu.View.StatusBar="Afeggag n waddad" +Basic.MainMenu.View.Fullscreen.Interface="Agrudem n ugdil aččuran" + +Basic.MainMenu.SceneCollection="Talkensit n yisuyas" +Basic.MainMenu.Profile="Amaɣnu" +Basic.MainMenu.Profile.Import="Kter amaɣnu" +Basic.MainMenu.Profile.Export="Sifeḍ amaɣnu" +Basic.MainMenu.SceneCollection.Import="Kter talkensit n yisuyas" +Basic.MainMenu.SceneCollection.Export="Sifeḍ talkensit n yisuyas" +Basic.MainMenu.Profile.Exists="Amaɣnu yella yakan" +Basic.MainMenu.SceneCollection.Exists="Talkensit n yisuyas tella yakan" + +Basic.MainMenu.Tools="Ifecka" + +Basic.MainMenu.Help="Tallelt" +Basic.MainMenu.Help.HelpPortal="Tawwurt n tallelt" +Basic.MainMenu.Help.Website="Rzu ar usmel web" +Basic.MainMenu.Help.Discord="Rnu ɣer uqeddac Discord" +Basic.MainMenu.Help.Logs="Ifuyla n uɣmis" +Basic.MainMenu.Help.Logs.ShowLogs="Beqqeḍ ifuyla n uɣmis" +Basic.MainMenu.Help.Logs.UploadCurrentLog="Sili afaylu n uɣmis amiran" +Basic.MainMenu.Help.Logs.UploadLastLog="Sili afaylu n uɣmis aneggaru" +Basic.MainMenu.Help.Logs.ViewCurrentLog="Beqqeḍ aɣmis amiran" +Basic.MainMenu.Help.CheckForUpdates="Nadi ileqman" +Basic.MainMenu.Help.CrashLogs="Ineqqisen n uɣelluy" +Basic.MainMenu.Help.CrashLogs.ShowLogs="Beqqeḍ ineqqisen n uɣelluy" +Basic.MainMenu.Help.CrashLogs.UploadLastLog="Sili aneqqis n uɣelluy aneggaru" +Basic.MainMenu.Help.About="Ɣef" + +Basic.Settings.ProgramRestart="Ahil isefk ad yales tanekkra akken ad ddun yiɣewwaren-agi." +Basic.Settings.ConfirmTitle="Sentem ibeddilen" +Basic.Settings.Confirm="Tesɛiḍ ibeddilen ur nettwasekles ara. Ad teskelseḍ ibeddilen?" + +Basic.Settings.General="Amatu" +Basic.Settings.General.Theme="Asentel" +Basic.Settings.General.Language="Tutlayt" +Basic.Settings.General.EnableAutoUpdates="Nadi ileqman s wudem awurman di tnekra" +Basic.Settings.General.OpenStatsOnStartup="Ldi adiwenni n tddadanin deg usekker" +Basic.Settings.General.WarnBeforeStartingStream="Beqqeḍ adiwenni n usentem mi ara yekker usuddem" +Basic.Settings.General.WarnBeforeStoppingStream="Beqqeḍ adiwenni n usentem mi ara yeḥbes usuddem" +Basic.Settings.General.WarnBeforeStoppingRecord="Beqqeḍ adiwenni n usentem mi ara yeḥbes usekles" +Basic.Settings.General.Projectors="Imagaren" +Basic.Settings.General.HideProjectorCursor="Ffer taḥnaccaḍt ɣef yimagaren" +Basic.Settings.General.ProjectorAlwaysOnTop="Yals ttarra imagaren nnig" +Basic.Settings.General.RecordWhenStreaming="Sekles s wudem awurman mi ara yetteddu usuddem" +Basic.Settings.General.KeepRecordingWhenStreamStops="Kemmel asekles mi ara yeḥbes usuddem" +Basic.Settings.General.ReplayBufferWhileStreaming="Sekker s wudem awurman tallunt n weḥraz n tulsa n tɣuri mi ara yetteddu usuddem" +Basic.Settings.General.KeepReplayBufferStreamStops="Eǧǧ tallunt n wephraz n tulsa n tɣuri termed mi ara yeḥbes usuddem" +Basic.Settings.General.SysTray="Taɣzut n telɣa" +Basic.Settings.General.SysTrayWhenStarted="Simẓi ɣer teɣzut n telɣa di tnekra" +Basic.Settings.General.SystemTrayHideMinimize="Yalas ssimẓi ɣer teɣzut n telɣa deg umɣiq n ufeggag n tmahilin" +Basic.Settings.General.SaveProjectors="Sekles imagaren mi ara teffɣeḍ" +Basic.Settings.General.Preview="Tadlayt" +Basic.Settings.General.OverflowHidden="Ffer tafuli" +Basic.Settings.General.OverflowAlwaysVisible="Taful tettban yalas" +Basic.Settings.General.OverflowSelectionHidden="Sken tafuli ɣas ma aɣbalu ur yettban ara" +Basic.Settings.General.Importers="Imaktaren" +Basic.Settings.General.AutomaticCollectionSearch="Nadi imeḍqan yettwassnen n telkensi n isuyas di tektert" +Basic.Settings.General.SwitchOnDoubleClick="Eg asaka ɣer usayes ma yella ussiti uslig" +Basic.Settings.General.StudioPortraitLayout="Sermed taneɣruft s tehri/s ibeddi" +Basic.Settings.General.TogglePreviewProgramLabels="Beqqeḍ tibzimin tamuɣli/ahil" +Basic.Settings.General.Multiview="Aṭas n tmuɣliwin" +Basic.Settings.General.Multiview.MouseSwitch="Ssit akken ad tbedeleḍ gar yisuyas" +Basic.Settings.General.Multiview.DrawSourceNames="Beqqeḍ ismawen n yisuyas" +Basic.Settings.General.Multiview.DrawSafeAreas="Suneɣ tiɣezza iḍemnen (EBU R 95)" +Basic.Settings.General.MultiviewLayout="Taneɣruft n waṭas n tmuɣliwin" +Basic.Settings.General.MultiviewLayout.Horizontal.Top="Aglawan, Afella (8 n yisuyas)" +Basic.Settings.General.MultiviewLayout.Horizontal.Bottom="Aglawan, Adda (8 n yisuyas)" +Basic.Settings.General.MultiviewLayout.Vertical.Left="Ubdid, Azelmaḍ (8 n yisuyas)" +Basic.Settings.General.MultiviewLayout.Vertical.Right="Ubdid, Ayfus (8 n yisuyas)" +Basic.Settings.General.MultiviewLayout.Horizontal.Extended.Top="Aglawan, Afella (24 n yisuyas)" + +Basic.Settings.Stream="Asuddem" +Basic.Settings.Stream.StreamType="Anaw n usuddem" +Basic.Settings.Stream.Custom.UseAuthentication="Seqdec asesteb" +Basic.Settings.Stream.Custom.Username="Isem n useqdac" +Basic.Settings.Stream.Custom.Password="Awal uffir" +Basic.Settings.Stream.BandwidthTestMode="Sermed askar n usekyed n tehri n tesfift" +Basic.Settings.Stream.TTVAddon.None="Ulac" +Basic.Settings.Stream.TTVAddon.Both="BetterTTV akked FrankerFaceZ" +Basic.Settings.Stream.MissingSettingAlert="Txuṣ twila n usuddem" +Basic.Settings.Stream.StreamSettingsWarning="Ldi iɣewwaren" +Basic.Settings.Stream.MissingUrl="URL n usuddem ixuṣ.\n\nLdi iɣewwaren akken ad tsekcmeḍ URL deg yiccer 'Asuddem'." +Basic.Settings.Stream.MissingStreamKey="Tasarut n usuddem txuṣ.\n\nLdi iɣewwaren akken ad tsekcmeḍ tasarut deg yiccer 'Asuddem'." +Basic.Settings.Stream.IgnoreRecommended="Ttu isemtar n umeẓlu n usuddem" +Basic.Settings.Stream.IgnoreRecommended.Warn.Title="Semselsi iɣewwaren yettwasmetren" +Basic.Settings.Stream.Recommended.MaxVideoBitrate="Aktum afellay n uvidyu: %1 kbps" +Basic.Settings.Stream.Recommended.MaxAudioBitrate="Aktum afellay n umeslaw: %1 kbps" +Basic.Settings.Stream.Recommended.MaxResolution="Tabadut tafellayt: %1" +Basic.Settings.Stream.Recommended.MaxFPS="FPS (ikataren i tasint) afellay: %1" + +Basic.Settings.Output="Tuffɣa" +Basic.Settings.Output.Format="Amasal n usekles" +Basic.Settings.Output.Encoder="Asettengal" +Basic.Settings.Output.SelectDirectory="Fren akaram n usekles" +Basic.Settings.Output.SelectFile="Fren afaylu n usekles" +Basic.Settings.Output.Mode="Askar n tuffɣa" +Basic.Settings.Output.Mode.Simple="Aḥerfi" +Basic.Settings.Output.Mode.Adv="Anaẓi" +Basic.Settings.Output.Mode.FFmpeg="Tuffɣa n FFmpeg" +Basic.Settings.Output.UseReplayBuffer="Sermed tallunt n weḥraz n tulsa n tɣuri" +Basic.Settings.Output.ReplayBuffer.SecondsMax="Tanzagt tafellayt n tulsa n tɣuri" +Basic.Settings.Output.ReplayBuffer.MegabytesMax="Takatut tefellayt (MAṬ)" +Basic.Settings.Output.Simple.SavePath="Abrid n usekles" +Basic.Settings.Output.Simple.RecordingQuality="Taɣara n usekles" +Basic.Settings.Output.Simple.RecordingQuality.Stream="Kifkif akked usuddem" +Basic.Settings.Output.Simple.RecordingQuality.Small="Taɣara tafellayt, tiddi n ukaram talemmast" +Basic.Settings.Output.Simple.Warn.Lossless.Msg="D tidet tebɣiḍ ad tesqedceḍ taɣara war asṛuḥu?" +Basic.Settings.Output.Simple.Warn.Lossless.Title="Alɣu ɣef tɣara war asṛuḥu!" +Basic.Settings.Output.Simple.Encoder.Software="Aseɣẓan (x264)" +Basic.Settings.Output.Simple.Encoder.Hardware.QSV="Arrum (QSV)" +Basic.Settings.Output.Simple.Encoder.Hardware.AMD="Arrum (AMD)" +Basic.Settings.Output.Simple.Encoder.Hardware.NVENC="Arrum (NVENC)" +Basic.Settings.Output.Simple.Encoder.SoftwareLowCPU="Aseɣẓan (x264 azwirɣewwar n useqdec amecṭuḥ n CPU, ad isimɣur tiddi n ufaylu)" +Basic.Settings.Output.Simple.TwitchVodTrack="Tazribt n Twitch VOD (Isseqdac tazribt 2)" +Basic.Settings.Output.Warn.EnforceResolutionFPS.Title="Tabadut/Framerate ur nemṣada ara" +Basic.Settings.Output.Warn.EnforceResolutionFPS.Resolution="Tabadut: %1" +Basic.Settings.Output.Warn.EnforceResolutionFPS.FPS="FPS: %1" +Basic.Settings.Output.VideoBitrate="Aktum n uvidyu" +Basic.Settings.Output.AudioBitrate="Aktum n umeslaw" +Basic.Settings.Output.Reconnect="Tulsa n tuqqna s wudem awurman" +Basic.Settings.Output.RetryDelay="Amenḍar send aneɛruḍ amaynut" +Basic.Settings.Output.MaxRetries="Amḍan afellay n yineɛruḍen" +Basic.Settings.Output.Advanced="Sermed iɣewwaren inaẓiyen n usettengal" +Basic.Settings.Output.EncoderPreset="Azwirɣewwar n usettengel" +Basic.Settings.Output.CustomEncoderSettings="Iɣewwaren yugnen n usettengal" +Basic.Settings.Output.NoSpaceFileName="Sirew isem n ufaylu war tallunt" + +Basic.Settings.Output.Adv.AudioTrack="Tazribt n umeslaw" +Basic.Settings.Output.Adv.Streaming="Asuddem" +Basic.Settings.Output.Adv.Audio.Track1="Tazribt 1" +Basic.Settings.Output.Adv.Audio.Track2="Tazribt 2" +Basic.Settings.Output.Adv.Audio.Track3="Tazribt 3" +Basic.Settings.Output.Adv.Audio.Track4="Tazribt 4" +Basic.Settings.Output.Adv.Audio.Track5="Tazribt 5" +Basic.Settings.Output.Adv.Audio.Track6="Tazribt 6" + +Basic.Settings.Output.Adv.Recording="Asekles" +Basic.Settings.Output.Adv.Recording.RecType="Anaw n usekles" +Basic.Settings.Output.Adv.Recording.Type="Anaw" +Basic.Settings.Output.Adv.Recording.Type.Standard="Aslugan" +Basic.Settings.Output.Adv.Recording.Type.FFmpegOutput="Tuffɣa yugnen (FFmpeg)" +Basic.Settings.Output.Adv.Recording.UseStreamEncoder="(Seqdec asettengal n usuddem)" +Basic.Settings.Output.Adv.Recording.Filename="Amasal n yisem n ufaylu" +Basic.Settings.Output.Adv.Recording.OverwriteIfExists="Sefsex afaylu yellan" +Basic.Settings.Output.Adv.FFmpeg.Type="Anaw n tuffɣa n FFmpeg" +Basic.Settings.Output.Adv.FFmpeg.Type.URL="Tuffɣa ɣer URL" +Basic.Settings.Output.Adv.FFmpeg.Type.RecordToFile="Tuffɣa ɣer Ufaylu" +Basic.Settings.Output.Adv.FFmpeg.SaveFilter.All="Akk ifuyla" +Basic.Settings.Output.Adv.FFmpeg.SavePathURL="Abrid n ufaylu neɣ URL" +Basic.Settings.Output.Adv.FFmpeg.Format="Amasal n unagbar" +Basic.Settings.Output.Adv.FFmpeg.FormatAudio="Ameslaw" +Basic.Settings.Output.Adv.FFmpeg.FormatVideo="Avidyu" +Basic.Settings.Output.Adv.FFmpeg.FormatDefault="Amsal n lexṣas" +Basic.Settings.Output.Adv.FFmpeg.FormatDesc="Aglam n umasal n lexṣas" +Basic.Settings.Output.Adv.FFmpeg.FormatDescDef="Akudak Ameslaw/avidyu yettwaf-d seg ubrid neɣ URL n ufaylu" +Basic.Settings.Output.Adv.FFmpeg.AVEncoderDefault="Asettengal n lexṣas" +Basic.Settings.Output.Adv.FFmpeg.AVEncoderDisable="Sens asettengal" +Basic.Settings.Output.Adv.FFmpeg.VEncoder="Asettengal n uvidyu" +Basic.Settings.Output.Adv.FFmpeg.VEncoderSettings="Iɣewwaren n usettengal n uvidyu (ma yella)" +Basic.Settings.Output.Adv.FFmpeg.AEncoder="Asettengal n umeslaw" +Basic.Settings.Output.Adv.FFmpeg.AEncoderSettings="Iɣewwaren n usettengal n umeslaw(ma yella)" +Basic.Settings.Output.Adv.FFmpeg.GOPSize="Azilal n yikataren yufraren (ikataren)" +Basic.Settings.Output.Adv.FFmpeg.IgnoreCodecCompat="Beqqeḍ akk ikudaken (ɣas ma zemren ad ilin ur mṣadan ara)" + +Screenshot="Tuṭṭfa n ugdil n tuffɣa" +Screenshot.SourceHotkey="Tuṭṭfa n ugdil n uɣbalu yettwafernen" +Screenshot.StudioProgram="Tuṭṭfa n ugdil (ahil)" +Screenshot.Preview="Tuṭṭfa n ugdil (tadlayt)" +Screenshot.Scene="Tuṭṭfa n ugdil (asayes)" +Screenshot.Source="Tuṭṭfa n ugdil (aɣbalu)" + + + +Basic.Settings.Video="Avidyu" +Basic.Settings.Video.BaseResolution="Tabadut tanaddayt (taɣzut n usuneɣ)" +Basic.Settings.Video.DisableAeroWindows="Sens Aero (Windows kan)" +Basic.Settings.Video.FPS="FPS" +Basic.Settings.Video.InvalidResolution="Azal n tbadut d armeɣtu. Isefk ad yili [width]x[height] (i.e. 1920x1080)" +Basic.Settings.Video.CurrentlyActive="Tuffɣa n uvidyu termed akka tura. Ma ulac uɣilif sens kra n tuffɣiwin akken ad tbeddeleḍ iɣewwaren n uvidyu." +Basic.Settings.Video.DisableAero="Sens Aero" + + +Basic.Settings.Audio="Ameslaw" +Basic.Settings.Audio.SampleRate="Atug n ulemmec" +Basic.Settings.Audio.Channels="Ibuda" +Basic.Settings.Audio.MeterDecayRate.Fast="Arurad" +Basic.Settings.Audio.MeterDecayRate.Medium="Alemmas (Anaw I PPM)" +Basic.Settings.Audio.MeterDecayRate.Slow="Ẓẓay (Anaw II PPM)" +Basic.Settings.Audio.Devices="Ibenkan n umeslaw ijemmalen" +Basic.Settings.Audio.DesktopDevice="Ameslaw n tnarit" +Basic.Settings.Audio.DesktopDevice2="Ameslaw n tnarit 2" +Basic.Settings.Audio.UnknownAudioDevice="[Ibenk ur yeqqin ara neɣ ur yewjid ara]" +Basic.Settings.Audio.Disabled="Yensa" + +Basic.Settings.Advanced="Anaẓi" +Basic.Settings.Advanced.General.ProcessPriority.High="Afellay" +Basic.Settings.Advanced.General.ProcessPriority.AboveNormal="Nnig n umagnu" +Basic.Settings.Advanced.General.ProcessPriority.Normal="Amagnu" +Basic.Settings.Advanced.General.ProcessPriority.BelowNormal="Ddaw n umagnu" +Basic.Settings.Advanced.Video.ColorFormat="Amasal n yini" +Basic.Settings.Advanced.Video.ColorSpace="Tallunt n yini" +Basic.Settings.Advanced.Video.ColorRange="Tagrumma n yini" +Basic.Settings.Advanced.Video.ColorRange.Partial="Abruyan" +Basic.Settings.Advanced.Video.ColorRange.Full="Ummid" +Basic.Settings.Advanced.Audio.MonitoringDevice.Default="Amezwar" +Basic.Settings.Advanced.StreamDelay="Asemmezger n usuddem" +Basic.Settings.Advanced.StreamDelay.Duration="Tanzagt" +Basic.Settings.Advanced.Network="Azeḍḍa" +Basic.Settings.Advanced.Network.BindToIP="Qqen ɣer IP" +Basic.Settings.Advanced.Hotkeys.NeverDisableHotkeys="Werǧin ad tsenseḍ inegzumen n unasiw" +Basic.Settings.Advanced.Hotkeys.DisableHotkeysInFocus="Sens inegzumen n unasiw ticki yella usaḍes ɣef usfaylu agejdan" +Basic.Settings.Advanced.Hotkeys.DisableHotkeysOutOfFocus="Sens inegzumen n unasiw ticki ulac asaḍes ɣef usfaylu agejdan" + +Basic.AdvAudio="Iraten inaẓiyen n uvidyu" +Basic.AdvAudio.ActiveOnly="Iɣbula urmiden kan" +Basic.AdvAudio.Name="Isem" +Basic.AdvAudio.Volume="Ableɣ" +Basic.AdvAudio.VolumeSource="Ableɣ i '%1'" +Basic.AdvAudio.Balance="Awliwal" +Basic.AdvAudio.BalanceSource="Awliwal i '%1'" +Basic.AdvAudio.SyncOffset="Asekḥer n umtawi" +Basic.AdvAudio.SyncOffsetSource="Asekḥer n umtawi i '%1'" +Basic.AdvAudio.AudioTracks="Tizribin" + +Basic.Settings.Hotkeys="Inegzumen n unasiw" +Basic.Settings.Hotkeys.Filter="Imzizdeg" + +Basic.Hotkeys.SelectScene="Ɛeddi ɣer usayes" + +Basic.SystemTray.Show="Sken" +Basic.SystemTray.Hide="Ffer" + +Basic.SystemTray.Message.Reconnecting="Yenser. Ala yettales tuqqna..." + +Hotkeys.Insert="Ger" +Hotkeys.Delete="Kkes" +Hotkeys.End="Taggara" +Hotkeys.PageUp="Asebter d asawen" +Hotkeys.PageDown="Asebter d akessar" +Hotkeys.ScrollLock="Sekkeṛ adrurem" +Hotkeys.Print="Siggez" +Hotkeys.Pause="Bedd" +Hotkeys.Left="Azelmaḍ" +Hotkeys.Right="Ayfus" +Hotkeys.Up="Asawen" +Hotkeys.Down="Akessar" +Hotkeys.Windows="Asfaylu" +Hotkeys.Menu="Umuɣ" +Hotkeys.Space="Tallunt" +Hotkeys.MouseButton="Amumed %1" + +Mute="Sens imesli" +Unmute="Sermed imesli" + +SceneItemShow="Beqqeḍ '%1'" +SceneItemHide="Ffer '%1'" + +OutputWarnings.NoTracksSelected="Isefk ad tferneḍ ma drus yiwet n tezribt" + +FinalScene.Title="Kkes asayes" +FinalScene.Text="Isefk ad yili ma drus yiwen n usayes." + +NoSources.Title="Ulac iɣbula" +NoSources.Text="Yettban-d am wakken ur terniḍ ara yakan kra n yiɣbula n uvidyu, ihi d agdil aberkan ara tsuffɣeḍ. D tidet tebɣiḍ ad tgeḍ ayagi?" +NoSources.Text.AddSource="Tzemreḍ ad ternuḍ iɣbula s usiti ɣef tignit + ddaw n tenkult n yiɣbula deg usfaylu agejdan di yal taswiɛt." +NoSources.Label="Ur tesɛiḍ ara yakan iɣbula.\nSsit ɣef tqeffalt + ukessar-agi,\nneɣ ssit s tqeffalt tayfust dagi akken ad ternuḍ yiwen." + +ChangeBG="Sbadu ini" +CustomColor="Ini yugnen" + + +About="Ɣef" +About.Info="OBS Studio d aseɣẓan ilelli n uɣbalu yeldin (open source) i wesekles n uvidyu akked usuddem s wakud ilaw." +About.Donate="Ɛiwen asenfaṛ" +About.GetInvolved="Ttekki" +About.Authors="Imeskaren" +About.License="Turagt" +About.Contribute="Dhel asenfar n OBS" + +AddUrl.Title="Rnu aɣbali si URL" +AddUrl.Text="Tzuɣreḍ URL ɣer OBS. Ayagi ad yernu s wudem awurman aseɣwen am uɣbalu. Ad tkemmeleḍ?" +AddUrl.Text.Url="URL: %1" + +ResizeOutputSizeOfSource="Beddel tiddi n tuffɣa (tiddi n uɣbalu)" +ResizeOutputSizeOfSource.Continue="Tebɣiḍ ad tkemmeleḍ?" + +PreviewTransition="Wali asaka" + +Importer="Amektar n telkensiyin n yisuyas" +Importer.SelectCollection="Fren talkensit n yisuyas" +Importer.Collection="Talkensit n yisuyas" +Importer.HelpText="Rnu ifuyla ɣer usfaylu-agi akken ad tketreḍ tilkensitin si OBS neɣ ihalen-nniḍen yettwadehlen." +Importer.Path="Abrid n telkensit" +Importer.Program="Yettwaf usnas" +Importer.AutomaticCollectionPrompt="Nadi s wudem awurman ɣef telkensiyin n yisuyas" +Importer.AutomaticCollectionText="OBS yezmer ad inadi s wudem awurman ɣef telkensiyin n yisuyas deg yihalen n wis kraḍ yettwadehlen. Tebɣiḍ OBS ad inadi s wudem awurman?\n\nTzemreḍ ad tbeddeleḍ areḍqal ayagi di Iɣewwaren >Amatu Imaktaren." + + +Restart="Ales asekker" +NeedsRestart="OBS Studio yesra ad yales tanekra. Tebɣiḍ ad talseḍ asekker tura?" + +ContextBar.NoSelectedSource="Ulac aɣbalu yettwafernen" +ContextBar.ResetTransform="Ales awennez n uselket" +ContextBar.FitToCanvas="Sezg ɣer teɣzut n usuneɣ" + +ContextBar.MediaControls.PlayMedia="Ɣer amidya" +ContextBar.MediaControls.PauseMedia="Ḥbes amidya" +ContextBar.MediaControls.StopMedia="Seḥbes amidya" +ContextBar.MediaControls.RestartMedia="Ales asekker n umidya" +ContextBar.MediaControls.PlaylistNext="Uḍfir di tebdart n tɣuri" +ContextBar.MediaControls.PlaylistPrevious="D uzwir di tebdart n tɣuri" +ContextBar.MediaControls.MediaProperties="Iraten n umidya" +ContextBar.MediaControls.BlindSeek="Awiǧit n tunigin deg umidya" + diff --git a/UI/data/locale/ko-KR.ini b/UI/data/locale/ko-KR.ini index 8b3cc2f..b847e75 100644 --- a/UI/data/locale/ko-KR.ini +++ b/UI/data/locale/ko-KR.ini @@ -93,7 +93,7 @@ LockVolume="음량 잠그기" LogViewer="로그 보기" ShowOnStartup="시작 시 보여주기" OpenFile="파일 열기" -AddValue="추가 %1" +AddValue="%1 추가" AlreadyRunning.Title="OBS가 이미 실행 중입니다" AlreadyRunning.Text="OBS가 이미 실행 중입니다! 의도한 것이 아니라면 새로운 OBS를 실행하기 전에 이미 동작 중인 프로그램을 종료하십시오. OBS가 시스템 트레이에 최소화되어 있는지도 확인하십시오." @@ -161,6 +161,7 @@ Basic.AutoConfig.StreamPage.DisconnectAccount="계정 연결끊기" Basic.AutoConfig.StreamPage.DisconnectAccount.Confirm.Title="해당 계정과 연결을 끊겠습니까?" Basic.AutoConfig.StreamPage.DisconnectAccount.Confirm.Text="이 변경 사항은 즉시 적용됩니다. 정말로 계정과 연결을 중단하겠습니까?" Basic.AutoConfig.StreamPage.GetStreamKey="스트림 키 받기" +Basic.AutoConfig.StreamPage.MoreInfo="자세한 정보" Basic.AutoConfig.StreamPage.UseStreamKey="스트림 키 사용" Basic.AutoConfig.StreamPage.Service="서비스" Basic.AutoConfig.StreamPage.Service.ShowAll="모두 보기..." @@ -216,16 +217,16 @@ Basic.Stats.ResetStats="통계 초기화" ResetUIWarning.Title="정말로 모든 UI를 초기화하겠습니까?" ResetUIWarning.Text="UI를 초기화하면 추가한 독이 안보일 것입니다. '보기' 메뉴에서 다시 나타나게 설정할 수 있습니다.\n\nUI를 초기화하겠습니까?" -Updater.Title="사용가능한 판올림이 있습니다" -Updater.Text="새 판올림이 준비되었습니다:" -Updater.UpdateNow="지금 판올림하기" +Updater.Title="새로운 업데이트를 사용할 수 있습니다" +Updater.Text="새 업데이트가 준비되었습니다:" +Updater.UpdateNow="지금 업데이트" Updater.RemindMeLater="나중에 다시 알림" -Updater.Skip="이번 판올림 건너뛰기" +Updater.Skip="업데이트 건너뛰기" Updater.Running.Title="현재 활성화된 프로그램" -Updater.Running.Text="판올림 전에 활성화되어 있는 출력을 먼저 꺼주세요" -Updater.NoUpdatesAvailable.Title="가능한 판올림이 없습니다" -Updater.NoUpdatesAvailable.Text="현재 사용가능한 판올림이 없습니다" -Updater.FailedToLaunch="판올림 도우미를 실행할 수 없습니다" +Updater.Running.Text="업데이트 전에 활성화 되어있는 출력을 먼저 꺼주세요" +Updater.NoUpdatesAvailable.Title="사용 가능한 업데이트가 없습니다" +Updater.NoUpdatesAvailable.Text="현재 사용가능한 업데이트가 없습니다" +Updater.FailedToLaunch="업데이트 관리자를 실행할 수 없습니다" Updater.GameCaptureActive.Title="게임 캡쳐 기능이 활성화 중" Updater.GameCaptureActive.Text="게임 캡쳐 라이브러리가 현재 사용 중입니다. 캡쳐 중인 게임/프로그램 혹은 윈도우를 종료 후 다시 시작하세요." @@ -329,7 +330,7 @@ Remux.ExitUnfinishedTitle="재다중화 작업 중" Remux.ExitUnfinished="재다중화 작업이 끝나지 않았습니다. 지금 멈추면 대상 파일은 사용할 수 없는 상태가 됩니다.\n정말로 작업을 중단하겠습니까?" Remux.HelpText="재다중화 작업을 하려면 파일을 이 창에 드롭하거나 비어있는 \"OBS 녹화\" 셀을 눌러 대상을 지정하세요." -UpdateAvailable="새 판올림 사용 가능" +UpdateAvailable="새 업데이트 사용 가능" UpdateAvailable.Text="버전 %1.%2.%3이 나왔습니다. 다운로드" Basic.DesktopDevice1="데스크탑 오디오" @@ -365,8 +366,8 @@ Deinterlacing.Yadif2x="야디프 2x" Deinterlacing.TopFieldFirst="상위 필드 우선" Deinterlacing.BottomFieldFirst="하단 필드 우선" -VolControl.SliderUnmuted="'%1'의 음량 조절: %2" -VolControl.SliderMuted="'%1'의 음량 조절: %2 (현재 음소거)" +VolControl.SliderUnmuted="'%1'의 음량 조절:" +VolControl.SliderMuted="'%1'의 음량 조절: (현재 음소거)" VolControl.Mute="음소거 '%1'" VolControl.Properties="'%1' 속성" @@ -382,6 +383,7 @@ Basic.Main.RenameSceneCollection.Title="장면 모음 이름 바꾸기" AddProfile.Title="프로파일 추가" AddProfile.Text="프로파일 이름을 입력하세요" +AddProfile.WizardCheckbox="자동 설정 마법사 보이기" RenameProfile.Title="프로파일 이름 바꾸기" @@ -396,6 +398,11 @@ Basic.SourceSelect.CreateNew="새로 만들기" Basic.SourceSelect.AddExisting="기존 추가" Basic.SourceSelect.AddVisible="소스를 표시" +Basic.Main.Sources.Visibility="투명도" +Basic.Main.Sources.VisibilityDescription="캔버스 안 '%1'의 투명도를 조절합니다" +Basic.Main.Sources.Lock="잠금" +Basic.Main.Sources.LockDescription="캔버스 안의 '%1'의 위치와 비율을 고정합니다" + Basic.PropertiesWindow="'%1' 속성" Basic.PropertiesWindow.AutoSelectFormat="%1 (자동선택: %2)" Basic.PropertiesWindow.SelectColor="색상 지정" @@ -567,7 +574,7 @@ 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="판올림 확인" +Basic.MainMenu.Help.CheckForUpdates="업데이트 확인" Basic.MainMenu.Help.CrashLogs="오류 보고(&R)" Basic.MainMenu.Help.CrashLogs.ShowLogs="오류 보고서 보기(&S)" Basic.MainMenu.Help.CrashLogs.UploadLastLog="마지막 오류 보고서 전송하기(&L)" @@ -580,7 +587,7 @@ Basic.Settings.Confirm="저장하지 않은 설정이 있습니다. 저장하시 Basic.Settings.General="일반" Basic.Settings.General.Theme="테마" Basic.Settings.General.Language="언어" -Basic.Settings.General.EnableAutoUpdates="프로그램을 시작할 때 자동으로 판올림이 있나 확인" +Basic.Settings.General.EnableAutoUpdates="프로그램을 시작할 때 자동으로 업데이트가 있나 확인하기" Basic.Settings.General.OpenStatsOnStartup="시작 시 통계 창을 열기" Basic.Settings.General.WarnBeforeStartingStream="방송을 시작할 때 확인 대화 상자 표시" Basic.Settings.General.WarnBeforeStoppingStream="방송을 중단할 때 확인 대화 상자 표시" @@ -635,13 +642,19 @@ Basic.Settings.Stream.StreamSettingsWarning="설정 열기" Basic.Settings.Stream.MissingUrlAndApiKey="URL 과 스트림 키가 없습니다.\n\n설정에 들어가 '방송'란에서 URL과 스트림 키를 입력하세요." Basic.Settings.Stream.MissingUrl="방송 URL이 없습니다.\n\n설정에 들어가 '방송'란에서 URL을 입력하세요." Basic.Settings.Stream.MissingStreamKey="스트림 키가 없습니다.\n\n설정에 들어가 '방송'란에서 스트림 키를 입력하세요." +Basic.Settings.Stream.IgnoreRecommended="권장 스트리밍 서비스 설정 무시" +Basic.Settings.Stream.IgnoreRecommended.Warn.Title="권장 설정 덮어쓰기" +Basic.Settings.Stream.IgnoreRecommended.Warn.Text="경고: 서비스 제한을 넘는 경우 방송의 품질이 저하되거나 막힐 수 있습니다.\n\n계속하시겠습니까?" +Basic.Settings.Stream.Recommended.MaxVideoBitrate="최대 영상 비트레이트: %1 kbps" +Basic.Settings.Stream.Recommended.MaxAudioBitrate="최대 오디오 비트레이트: %1 kbps" +Basic.Settings.Stream.Recommended.MaxResolution="최대 해상도: %1" +Basic.Settings.Stream.Recommended.MaxFPS="최대 FPS: %1" 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.DynamicBitrate="네트워크 혼잡 상태를 관리하기 위해서 비트레이트를 유동적으로 변경합니다" Basic.Settings.Output.DynamicBitrate.Beta="네트워크 혼잡 상태를 관리하기 위해서 비트레이트를 유동적으로 변경합니다 (베타)" Basic.Settings.Output.DynamicBitrate.TT="혼잡을 줄이기 위해 프레임을 떨어뜨리는 대신 적용 중인 비트레이트를 유동적으로 조절합니다.\n\n중대한 혼잡 상태가 급작스럽게 발생할 때 시청자들이 접하는 화면이 어느정도 지체될 수 있습니다.\n비트레이트가 감소하면 복구하는데 수 분이 걸릴 수 있습니다.\n\n이 기능은 현재 RTMP에서만 지원합니다." @@ -662,8 +675,8 @@ 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.VideoBitrate="경고: 송출 영상의 비트레이트가 현재 스트리밍 서비스의 최대값을 넘는 %1 으로 설정됩니다." +Basic.Settings.Output.Simple.Warn.AudioBitrate="경고: 송출 오디오의 비트레이트가 현재 스트리밍 서비스의 최대값을 넘는 %1 으로 설정됩니다." Basic.Settings.Output.Simple.Warn.CannotPause="경고: 녹화 품질이 \"방송과 동일\"로 설정되어 있으면 녹화를 일시정지할 수 없습니다." Basic.Settings.Output.Simple.Warn.Encoder="경고: 방송과 녹화를 동시에 진행할 때 다음을 주의하십시오. 소프트웨어 인코더로 방송과 다른 품질로 녹화하면 더 많은 CPU 부담이 발생합니다." Basic.Settings.Output.Simple.Warn.Lossless="경고: 무손실 품질로 녹화하면 파일 크기가 엄청나게 커집니다! 해당 설정은 높은 해상도 및 프레임에서 분당 7기가바이트 이상 필요합니다. 따라서 디스크에 아주 큰 공간을 확보하지 않는 이상 장시간 녹화에는 추천하지 않습니다." @@ -674,6 +687,11 @@ 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.Simple.TwitchVodTrack="트위치 다시보기 트랙 (2번 트랙 사용)" +Basic.Settings.Output.Warn.EnforceResolutionFPS.Title="호환되지 않는 해상도/프레임률" +Basic.Settings.Output.Warn.EnforceResolutionFPS.Msg="이 스트리밍 서비스는 현재 출력 해상도 및/또는 프레임률을 지원하지 않습니다. 호환 가능한 가장 가까운 값으로 변경할 것입니다.:\n\n%1\n\n계속하시겠습니까?" +Basic.Settings.Output.Warn.EnforceResolutionFPS.Resolution="해상도: %1" +Basic.Settings.Output.Warn.EnforceResolutionFPS.FPS="FPS: %1" Basic.Settings.Output.VideoBitrate="비디오 비트레이트" Basic.Settings.Output.AudioBitrate="오디오 비트레이트" Basic.Settings.Output.Reconnect="자동으로 다시 연결" @@ -688,15 +706,16 @@ 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.Audio.Track5="트랙 5" Basic.Settings.Output.Adv.Audio.Track6="트랙 6" +Basic.Settings.Output.Adv.TwitchVodTrack="Twitch VOD 트랙" Basic.Settings.Output.Adv.Recording="녹화" +Basic.Settings.Output.Adv.Recording.RecType="녹화 형식" Basic.Settings.Output.Adv.Recording.Type="형식" Basic.Settings.Output.Adv.Recording.Type.Standard="표준" Basic.Settings.Output.Adv.Recording.Type.FFmpegOutput="임의 출력 (FFmpeg)" @@ -824,13 +843,18 @@ Basic.AdvAudio="오디오 고급 설정" Basic.AdvAudio.ActiveOnly="활성화된 소스만" Basic.AdvAudio.Name="이름" Basic.AdvAudio.Volume="음량" +Basic.AdvAudio.VolumeSource="'%1' 소리 크기" Basic.AdvAudio.Mono="모노" +Basic.AdvAudio.MonoSource="'%1' 모노 다운믹싱" Basic.AdvAudio.Balance="균형" +Basic.AdvAudio.BalanceSource="'%1' 밸런싱" Basic.AdvAudio.SyncOffset="싱크 오프셋" +Basic.AdvAudio.SyncOffsetSource="'%1' 싱크 조절" Basic.AdvAudio.Monitoring="오디오 모니터링" Basic.AdvAudio.Monitoring.None="모니터링 끔" Basic.AdvAudio.Monitoring.MonitorOnly="모니터링만 (출력은 제거)" Basic.AdvAudio.Monitoring.Both="모니터링과 출력" +Basic.AdvAudio.MonitoringSource="'%1' 오디오 모니터링" Basic.AdvAudio.AudioTracks="트랙" Basic.Settings.Hotkeys="단축키" diff --git a/UI/data/locale/ku-TR.ini b/UI/data/locale/ku-TR.ini index 8cf7099..14fb49d 100644 --- a/UI/data/locale/ku-TR.ini +++ b/UI/data/locale/ku-TR.ini @@ -128,6 +128,7 @@ ConfirmExit.Title="ده‌رچوون لە OBS" + Basic.TransformWindow.Position="شوێن" diff --git a/UI/data/locale/lt-LT.ini b/UI/data/locale/lt-LT.ini index 406aa3a..02d4078 100644 --- a/UI/data/locale/lt-LT.ini +++ b/UI/data/locale/lt-LT.ini @@ -35,6 +35,9 @@ StudioProgramWindow="Ne pilno ekrano projekcija (Programa)" PreviewWindow="Ne pilno ekrano projekcija (Peržiūra)" SceneWindow="Ne pilno ekrano projekcija (Scena)" SourceWindow="Ne pilno ekrano projekcija (Šaltinis)" +MultiviewProjector="Daugialypė peržiūra (Per visą ekraną)" +MultiviewWindowed="Daugialypė peržiūra (Per dalį ekrano)" +ResizeProjectorWindowToContent="Pritaikyti langą prie turinio" Clear="Išvalyti" Revert="Atstatyti" Show="Parodyti" @@ -49,6 +52,7 @@ ResetOSXVSyncOnExit="Iš naujo nustatyti macOS V-Sync išeinant" HighResourceUsage="Kodavimas perkrautas! Mažinkite vaizdo parametrus arba naudokite greitesnę kodavimo parengtį." Transition="Perėjimas" QuickTransitions="Greitieji perėjimai" +FadeToBlack="Pereiti į juodą" Left="Iš kairės" Right="Iš dešinės" Top="Iš viršaus" @@ -57,24 +61,41 @@ Reset="Atstatyti" Hours="Valandos" Minutes="Minutės" Seconds="Sekundės" +Deprecated="Nebenaudojamas" +ReplayBuffer="Pakartojimo ribotuvas" Import="Importuoti" Export="Eksportuoti" Copy="Kopijuoti" Paste="Įklijuoti" +PasteReference="Įklijuoti (Nuoroda)" +PasteDuplicate="Įklijuoti (Duplikatas)" Next="Kitas" Back="Atgal" Defaults="Numatytieji" +HideMixer="Paslėpti maišyklėje" None="Nieko" StudioMode.Preview="Peržiūra" StudioMode.Program="Programa" +ShowInMultiview="Rodyti daugialypėje peržiūroje" Group="Grupė" +DoNotShowAgain="Daugiau nerodyti" Default="(Numatytas)" +Calculating="Skaičiuojama..." Fullscreen="Visas ekranas" Percent="Procentai" +AspectRatio="Kraštinių santykis %1:%2" +LockVolume="Užrakinti garsą" +LogViewer="Peržiūrėti žurnalą" +ShowOnStartup="Rodyti paleidžiant" +OpenFile="Atidaryti failą" +AddValue="Pridėti %1" AlreadyRunning.Title="OBS jau yra ijungtas" +AlreadyRunning.Text="OBS jau paleistas! Nebent jūs norėjote taip padaryti, prašome išjungti esančius OBS procesus prieš paleidžiant naują. Jeigu turite nusistatę OBS susimažinti į paslėptas piktogramas, prašome pažiūrėti ar programa vis dar veikia ten." AlreadyRunning.LaunchAnyway="Vistiek paleisti" +ChromeOS.Title="Nepalaikoma platforma" +ChromeOS.Text="OBS panašu, kad veikia ChromeOS sistemoje. Ši platforma yra nepalaikoma" @@ -83,6 +104,8 @@ Auth.AuthFailure.Title="Autentifikacijos klaida" Auth.InvalidScope.Title="Reikalingas autentifikavimas" Auth.Chat="chat'as" Auth.StreamInfo="Transliacijos informacija" +TwitchAuth.Stats="Twitch statistika" +TwitchAuth.Feed="Twitch aktyvumo sąrašas" Copy.Filters="Kopijuoti filtrus" @@ -95,11 +118,21 @@ BandwidthTest.Region.Other="Kita" Basic.AutoConfig.ApplySettings="Taikyti nustatymus" Basic.AutoConfig.StartPage="Naudojimo informacija" +Basic.AutoConfig.StartPage.PrioritizeRecording="Optimizuoti tik įrašymui, aš netransliuosiu" Basic.AutoConfig.VideoPage="Video nustatymai" Basic.AutoConfig.StreamPage="Transliacijos informacija" +Basic.AutoConfig.StreamPage.ConnectAccount="Prijungti paskyrą (rekomenduojama)" +Basic.AutoConfig.StreamPage.DisconnectAccount="Atjungti paskyrą" +Basic.AutoConfig.StreamPage.DisconnectAccount.Confirm.Title="Atjungti paskyrą?" +Basic.AutoConfig.StreamPage.DisconnectAccount.Confirm.Text="Šis pakeitimas įsigalios iš karto. Ar esate įsitikinę, kad norite atjungti paskyrą?" +Basic.AutoConfig.StreamPage.GetStreamKey="Gauti transliacijos raktą" +Basic.AutoConfig.StreamPage.MoreInfo="Daugiau informacijos" Basic.AutoConfig.StreamPage.UseStreamKey="Naudoti transliacijos raktą" Basic.AutoConfig.StreamPage.Service="Platforma" +Basic.AutoConfig.StreamPage.Service.ShowAll="Rodyti visus..." +Basic.AutoConfig.StreamPage.Service.Custom="Pasirinktinis..." Basic.AutoConfig.StreamPage.Server="Serveris" +Basic.AutoConfig.StreamPage.StreamKey="Transliacijos raktas" Basic.AutoConfig.StreamPage.StreamKey.LinkToSite="(Nuoroda)" Basic.Stats.Output.Stream="Transliacija" @@ -246,6 +279,7 @@ Basic.SourceSelect.CreateNew="Sukurti naują" Basic.SourceSelect.AddExisting="Pridėti esamą" Basic.SourceSelect.AddVisible="Padaryti šaltinį matomu" + Basic.PropertiesWindow="'%1' savybės" Basic.PropertiesWindow.AutoSelectFormat="%1 (automatinis pasirinkimas: %2)" Basic.PropertiesWindow.SelectColor="Pasirinkti spalvą" diff --git a/UI/data/locale/mn-MN.ini b/UI/data/locale/mn-MN.ini index 5cc298a..1f6994d 100644 --- a/UI/data/locale/mn-MN.ini +++ b/UI/data/locale/mn-MN.ini @@ -123,6 +123,7 @@ Basic.AutoConfig.StreamPage.ConnectAccount="Хэрэглэгчийг холбо Basic.AutoConfig.StreamPage.DisconnectAccount="Хэрэглэгчийг салгах" Basic.AutoConfig.StreamPage.DisconnectAccount.Confirm.Title="Хэрэглэгчийг салгах уу?" Basic.AutoConfig.StreamPage.GetStreamKey="Цацалтын түлхүүр үгс авах" +Basic.AutoConfig.StreamPage.MoreInfo="Илүү мэдээлэл" Basic.AutoConfig.StreamPage.UseStreamKey="Цацалтын түлхүүр үгс хэрэглэх" Basic.AutoConfig.StreamPage.Service="Үйлчилгээ" Basic.AutoConfig.StreamPage.Service.ShowAll="Бүгдийг харуул..." @@ -232,6 +233,7 @@ Basic.Main.RenameSceneCollection.Title="Хөшигний цуглуулганы + Basic.PropertiesWindow.SelectColor="Өнгө сонгох" Basic.PropertiesWindow.SelectFont="Фонт сонгох" @@ -324,7 +326,6 @@ Basic.Settings.Output.Format="Бичлэгийн формат" Basic.Settings.Output.Encoder="Кодлогч" Basic.Settings.Output.SelectDirectory="Бичлэгийн Лавлахыг Сонгох" Basic.Settings.Output.SelectFile="Бичлэгийн Файлыг Сонго" -Basic.Settings.Output.EnforceBitrate="Шууд цацалтын сервcийy хурдыг хязгаарлах" Basic.Settings.Output.Mode="Гаралтын Горим" Basic.Settings.Output.Mode.Simple="Энгийн" Basic.Settings.Output.Mode.Adv="Дэвшилттэй" diff --git a/UI/data/locale/ms-MY.ini b/UI/data/locale/ms-MY.ini index 22bf7cb..f5ee774 100644 --- a/UI/data/locale/ms-MY.ini +++ b/UI/data/locale/ms-MY.ini @@ -221,6 +221,7 @@ Basic.SourceSelect.CreateNew="Cipta baru" Basic.SourceSelect.AddExisting="Tambah Sedia Ada" Basic.SourceSelect.AddVisible="Jadikan Sumber Kelihatan" + Basic.PropertiesWindow="Sifat-sifat untuk '%1'" Basic.PropertiesWindow.AutoSelectFormat="%1 (auto-pilih: %2)" Basic.PropertiesWindow.SelectColor="Pilih warna" @@ -354,7 +355,6 @@ Basic.Settings.Stream.StreamType="Jenis 'Stream'" Basic.Settings.Output="Hasil" Basic.Settings.Output.Format="Format Rakaman" Basic.Settings.Output.SelectFile="Pilih Fail Rakaman" -Basic.Settings.Output.EnforceBitrate="Kuatkuasakan had nilai bit perkhidmatan 'streaming'" Basic.Settings.Output.Mode.Simple="Mudah" Basic.Settings.Output.Mode.Adv="Lanjutan" Basic.Settings.Output.Simple.RecordingQuality="Kualiti Rakaman" diff --git a/UI/data/locale/nb-NO.ini b/UI/data/locale/nb-NO.ini index 7ba0130..fc87c76 100644 --- a/UI/data/locale/nb-NO.ini +++ b/UI/data/locale/nb-NO.ini @@ -37,6 +37,7 @@ SceneWindow="Projektor i vindu (scene)" SourceWindow="Projektor i vindu (kilde)" MultiviewProjector="Flervisning (Fullskjerm)" MultiviewWindowed="Flervisning (Vindu)" +ResizeProjectorWindowToContent="Tilpass vindu til innhold" Clear="Tøm" Revert="Tilbakestill" Show="Vis" @@ -86,13 +87,19 @@ Calculating="Kalkulerer..." Fullscreen="Fullskjerm" Windowed="Vindusbasert" Percent="Prosent" +RefreshBrowser="Oppdater" AspectRatio="Størrelsesforhold %1:%2" LockVolume="Lås volum" +LogViewer="Logg leser" +ShowOnStartup="Vis ved oppstart" +OpenFile="Åpne fil" AlreadyRunning.Title="OBS kjører allerede" AlreadyRunning.Text="OBS kjører allerede! Med mindre du ikke mente dette, vennligst lukk alle eksisterende kjørende tilfeller av OBS før du kjører noen nye. Hvis du har satt OBS til å minimere til systemkurven, vennligst sjekk om den fortsatt kjører der." AlreadyRunning.LaunchAnyway="Start uansett" +ChromeOS.Title="Usupportert platform" +ChromeOS.Text="OBS ser ut til å kjøre i en ChromeOS kontainer. Denne platformen er ikke supportert" DockCloseWarning.Title="Lukker festbart vindu" DockCloseWarning.Text="Du stengte nettopp et festbart vindu. Hvis du vil vise det igjen, kan du gå til Vis → Festede elementer i menylinjen." @@ -137,7 +144,9 @@ Basic.AutoConfig.StartPage="Bruksinformasjon" Basic.AutoConfig.StartPage.SubTitle="Angi hva du vil bruke programmet til" Basic.AutoConfig.StartPage.PrioritizeStreaming="Optimaliser for strømming, innspilling kommer i andre rekke" Basic.AutoConfig.StartPage.PrioritizeRecording="Optimaliser for innspilling, jeg skal ikke streame" +Basic.AutoConfig.StartPage.PrioritizeVirtualCam="Jeg har kun behov for det virtuelle kamera" Basic.AutoConfig.VideoPage="Videoinnstillinger" +Basic.AutoConfig.VideoPage.SubTitle="Velg video innstillingene du ønsker å bruke" Basic.AutoConfig.VideoPage.BaseResolution.UseCurrent="Bruk Gjeldende (%1x%2)" Basic.AutoConfig.VideoPage.BaseResolution.Display="Skjerm %1 (%2x%3)" Basic.AutoConfig.VideoPage.FPS.UseCurrent="Bruk Gjeldende (%1)" @@ -179,6 +188,8 @@ Basic.AutoConfig.TestPage.Result.StreamingEncoder="Kringkastingsenkoder" Basic.AutoConfig.TestPage.Result.RecordingEncoder="Opptakskoder" Basic.AutoConfig.TestPage.Result.Header="Programmet har estimert at disse innstillingene er den mest ideelle for deg:" Basic.AutoConfig.TestPage.Result.Footer="For å bruke disse innstillingene, klikker du Bruk innstillinger. Å konfigurere veiviseren og prøv på nytt, klikker du tilbake. For å konfigurer innstillinger manuelt selv, klikk Avbryt og åpne innstillinger." +Basic.AutoConfig.Info="Veiviseren for automatisk konfigurasjon finner de beste innstillingene basert på din datamaskins spesifikasjon og internetthastighet." +Basic.AutoConfig.RunAnytime="Denne kan kjøre når som helst ved å gå til verktøy menyen." Basic.Stats="Statistikk" Basic.Stats.CPUUsage="CPU-bruk" @@ -293,7 +304,10 @@ Output.BadPath.Title="Ugyldig Filbane" Output.BadPath.Text="Den oppgitte fillagringsbanen er ugyldig. Vennligst sjekk innstillingene dine og bekreft at filbanen er gyldig." LogReturnDialog="Vellykket Loggopplasting" +LogReturnDialog.Description="Loggfilen din har blitt lastet opp. Du kan nå dele linken for feilsøking eller til støtteformål." +LogReturnDialog.Description.Crash="Kræsjrapporten har blit lastet opp. Du kan nå dele linken for feilsøkingsformål." LogReturnDialog.CopyURL="Kopiér URL" +LogReturnDialog.AnalyzeURL="Analyser" LogReturnDialog.ErrorUploadingLog="Feil ved opplasting av loggfil." Remux.SourceFile="OBS-opptak" @@ -350,8 +364,6 @@ Deinterlacing.Yadif2x="Dobbel-Yadif" Deinterlacing.TopFieldFirst="Øverste felt først" Deinterlacing.BottomFieldFirst="Nederste felt først" -VolControl.SliderUnmuted="Volumskyveknappen for '%1': %2" -VolControl.SliderMuted="Volumskyveknappen for '%1': %2 (dempet)" VolControl.Mute="Demp '%1'" VolControl.Properties="Egenskaper for '%1'" @@ -381,6 +393,7 @@ Basic.SourceSelect.CreateNew="Opprett" Basic.SourceSelect.AddExisting="Legg til eksisterende" Basic.SourceSelect.AddVisible="Gjør kilden synlig" + Basic.PropertiesWindow="Egenskaper for '%1'" Basic.PropertiesWindow.AutoSelectFormat="%1 (selvvalg: %2)" Basic.PropertiesWindow.SelectColor="Velg farge" @@ -457,6 +470,7 @@ Basic.Main.StartRecording="Start Opptak" Basic.Main.StartReplayBuffer="Start omspillingsbuffer" Basic.Main.SaveReplay="Lagre reprise" Basic.Main.StartStreaming="Start Strømming" +Basic.Main.StartVirtualCam="Start virtuelt kamera" Basic.Main.StopRecording="Stopp Opptak" Basic.Main.PauseRecording="Sett opptaket på pause" Basic.Main.UnpauseRecording="Fortsett opptaket" @@ -466,6 +480,9 @@ Basic.Main.StoppingReplayBuffer="Stopper omspillingsbufferen..." Basic.Main.StopStreaming="Stopp Strømming" Basic.Main.StoppingStreaming="Avslutter sendingen …" Basic.Main.ForceStopStreaming="Avslutt sendingen (forkast forsinkelse)" +Basic.Main.ShowContextBar="Vis verktøylinje for kilde" +Basic.Main.HideContextBar="Skjul verktøylinje for kilde" +Basic.Main.StopVirtualCam="Stopp virtuelt kamera" Basic.Main.Group="Gruppe %1" Basic.Main.GroupItems="Gruppér merkede gjenstander" Basic.Main.Ungroup="Adskill" @@ -521,6 +538,8 @@ Basic.MainMenu.View.Docks="Festede elementer" Basic.MainMenu.View.Docks.ResetUI="Omstart grensesnittet" Basic.MainMenu.View.Docks.LockUI="Lås grensesnittet" Basic.MainMenu.View.Docks.CustomBrowserDocks="Tilpassede nettleseroppgavelinjer..." +Basic.MainMenu.View.ListboxToolbars="Knapper for Scene/Kilder" +Basic.MainMenu.View.ContextBar="Verktøylinje for kilde" Basic.MainMenu.View.SceneTransitions="S&ceneoverganger" Basic.MainMenu.View.SourceIcons="Kilde &ikoner" Basic.MainMenu.View.StatusBar="&Statuslinje" @@ -620,7 +639,6 @@ Basic.Settings.Output.Format="Opptaksformat" Basic.Settings.Output.Encoder="Koder" Basic.Settings.Output.SelectDirectory="Velg opptaksmappe" Basic.Settings.Output.SelectFile="Velg opptaksfil" -Basic.Settings.Output.EnforceBitrate="Håndhev strømmetjenestens bitfrekvensgrense" Basic.Settings.Output.DynamicBitrate="Endre bitrate dynamisk for å håndtere overbelastning" Basic.Settings.Output.DynamicBitrate.Beta="Endre bitrate dynamisk for å håndtere overbelastning (Beta)" Basic.Settings.Output.DynamicBitrate.TT="I stedet for å droppe bilderuter for å redusere overbelastning, endres bitrate dynamisk underveis.\n\nMerk at dette kan øke forsinkelsen for seerne hvis det plutselig er en betydelig overbelastning.\nNår bitraten synker, kan gjenopprettingen ta opp mot noen minutter.\n\nFor øyeblikket støttes bare RTMP." @@ -641,8 +659,6 @@ Basic.Settings.Output.Simple.RecordingQuality.Stream="Samme som strøm" Basic.Settings.Output.Simple.RecordingQuality.Small="Høy kvalitet, middels filstørrelse" Basic.Settings.Output.Simple.RecordingQuality.HQ="Veldig høy kvalitet, stor filstørrelse" Basic.Settings.Output.Simple.RecordingQuality.Lossless="Tapsfri kvalitet, veldig stor filstørrelse" -Basic.Settings.Output.Simple.Warn.VideoBitrate="Advarsel: Strømmens bitfrekvens vil bli satt til %1, som er den øvre grensen for den gjeldende strømmetjenesten. Om du ønsker å gå over %1, må du aktivere avanserte koderinnstillinger og sørge for at valget for håndheving av strømmetjenestens grense ikke er huket av." -Basic.Settings.Output.Simple.Warn.AudioBitrate="Advarsel: Strømmens lydbitfrekvens vil bli satt til %1, som er den øvre grensen for den gjeldende strømmetjenesten. Om du ønsker å gå over %1, må du aktivere avanserte koderinnstillinger og sørge for at valget for håndheving av strømmetjenestens grense ikke er huket av." Basic.Settings.Output.Simple.Warn.CannotPause="Advarsel: Innspillinger kan ikke pauses hvis opptakskvaliteten er satt til \"Samme som strøm\"." Basic.Settings.Output.Simple.Warn.Encoder="Advarsel: Opptak med programvarekoder i en annen kvalitetsinnstilling enn strømmingen vil kreve ekstra prosessorressurser om du strømmer og tar opp på samme tid." Basic.Settings.Output.Simple.Warn.Lossless="Advarsel: Tapsfri kvalitet resulterer i enormt store filstørrelser! Denne innstillingen kan bruke oppimot 7 GB diskplass per minutt ved opptak med høy oppløsning og bildefrekvens. Tapsfri kvalitet anbefales ikke for lange opptak med mindre du har store mengder diskplass tilgjengelig." @@ -667,7 +683,6 @@ Basic.Settings.Output.NoSpaceFileName="Lag filnavn uten mellomrom" Basic.Settings.Output.Adv.Rescale="Reskaler utgang" Basic.Settings.Output.Adv.AudioTrack="Lydspor" Basic.Settings.Output.Adv.Streaming="Strømming" -Basic.Settings.Output.Adv.ApplyServiceSettings="Fremtving strømmetjenestens koderinnstillinger" Basic.Settings.Output.Adv.Audio.Track1="Spor 1" Basic.Settings.Output.Adv.Audio.Track2="Spor 2" Basic.Settings.Output.Adv.Audio.Track3="Spor 3" @@ -704,6 +719,12 @@ Basic.Settings.Output.Adv.FFmpeg.MuxerSettings="Mukserinnstillinger (om noen)" Basic.Settings.Output.Adv.FFmpeg.GOPSize="Nøkkelbildeintervall (bilder)" Basic.Settings.Output.Adv.FFmpeg.IgnoreCodecCompat="Vis alle kodeker (selv om potensielt ikke-kompatibel)" +Screenshot="Skjermbilde av forhåndsvisning" +Screenshot.SourceHotkey="Skjermbilde av valgt kilde" +Screenshot.StudioProgram="Skjermbilde (program)" +Screenshot.Preview="Skjermbilde (forhåndsvisning)" +Screenshot.Scene="Skjermbilde (Scene)" +Screenshot.Source="Skjermbilde (Kilde)" @@ -727,6 +748,7 @@ Basic.Settings.Video.DisableAero="Skru av Aero" Basic.Settings.Video.DownscaleFilter.Bilinear="Bilineær (raskest, men uskarp ved skalering)" Basic.Settings.Video.DownscaleFilter.Bicubic="Bikubisk (skjerpet skalering, 16 prøver)" Basic.Settings.Video.DownscaleFilter.Lanczos="Lanczos (skjerpet skalering, 36 prøver)" +Basic.Settings.Video.DownscaleFilter.Area="Område (Vektet sum, 4/6/9 målinger)" Basic.Settings.Audio="Lyd" Basic.Settings.Audio.SampleRate="Samplingsfrekvens" @@ -742,6 +764,7 @@ Basic.Settings.Audio.PeakMeterType.TruePeak="Ekte toppunkt (Høyere CPU-bruk)" Basic.Settings.Audio.MultiChannelWarning.Enabled="Advarsel: Surroundlyd er aktivert." Basic.Settings.Audio.MultichannelWarning.Title="Vil du aktivere surround-lyd?" Basic.Settings.Audio.MultichannelWarning.Confirm="Er du sikker på at du vil aktivere surround-lyd?" +Basic.Settings.Audio.Devices="Globale lyd enheter" Basic.Settings.Audio.DesktopDevice="Skrivebordslyd" Basic.Settings.Audio.DesktopDevice2="Skrivebordslyd 2" Basic.Settings.Audio.AuxDevice="Mikrofon/Aux" @@ -905,5 +928,16 @@ Importer.AutomaticCollectionText="OBS kan automatisk finne importerbare scenekol Restart="Omstart" NeedsRestart="OBS Studio må startes på nytt. Vil du starte på nytt nå?" +ContextBar.NoSelectedSource="Ingen kilde er valgt" +ContextBar.ResetTransform="Tilbakestill transformering" +ContextBar.FitToCanvas="Tilpass til lerret" +ContextBar.MediaControls.PlayMedia="Spill av media" +ContextBar.MediaControls.PauseMedia="Pause media" +ContextBar.MediaControls.StopMedia="Stop media" +ContextBar.MediaControls.RestartMedia="Start media på nytt" +ContextBar.MediaControls.PlaylistNext="Neste i Spilleliste" +ContextBar.MediaControls.PlaylistPrevious="Forrige i spilleliste" +ContextBar.MediaControls.MediaProperties="Media egenskaper" +ContextBar.MediaControls.BlindSeek="Widget for media søker" diff --git a/UI/data/locale/nl-NL.ini b/UI/data/locale/nl-NL.ini index 4e6a105..367cb71 100644 --- a/UI/data/locale/nl-NL.ini +++ b/UI/data/locale/nl-NL.ini @@ -6,7 +6,7 @@ Apply="Toepassen" Cancel="Annuleren" Close="Sluiten" Save="Opslaan" -Discard="Annuleren" +Discard="Negeren" Disable="Uitschakelen" Yes="Ja" No="Nee" @@ -22,7 +22,7 @@ Settings="Instellingen" Display="Beeldscherm" Name="Naam" Exit="Afsluiten" -Mixer="Audio Mixer" +Mixer="Audiomixer" Browse="Bladeren" Mono="Mono" Stereo="Stereo" @@ -37,7 +37,7 @@ SceneWindow="Projectorvenster (Scène)" SourceWindow="Projectorvenster (Bron)" MultiviewProjector="Multiview (Fullscreen)" MultiviewWindowed="Multiview (Venster)" -ResizeProjectorWindowToContent="Venster aanpassen naar inhoud" +ResizeProjectorWindowToContent="Venster aanpassen aan de inhoud" Clear="Wissen" Revert="Herstellen" Show="Weergeven" @@ -66,7 +66,7 @@ ReplayBuffer="Replay Buffer" Import="Importeer" Export="Exporteer" Copy="Kopiëren" -Paste="plakken" +Paste="Plakken" PasteReference="Plakken (referentie)" PasteDuplicate="Plakken (dupliceren)" RemuxRecordings="Remux opnames" @@ -76,18 +76,18 @@ Defaults="Standaardwaarden" HideMixer="Verbergen in mixer" TransitionOverride="Overgang overschrijven" None="Geen" -StudioMode.Preview="Voorbeeld" +StudioMode.Preview="Voorvertoning" StudioMode.Program="Programma" ShowInMultiview="Weergeven in Multiview" -VerticalLayout="Verticale Lay-out" +VerticalLayout="Verticale layout" Group="Groep" DoNotShowAgain="Niet opnieuw tonen" Default="(Standaard)" Calculating="Berekenen..." Fullscreen="Volledig scherm" -Windowed="Venster" +Windowed="In een venster" Percent="Procent" -RefreshBrowser="Herlaad" +RefreshBrowser="Opnieuw laden" AspectRatio="Beeldverhouding %1:%2" LockVolume="Volume vergrendelen" LogViewer="Log Bekijker" @@ -97,23 +97,23 @@ AddValue="%1 toevoegen" AlreadyRunning.Title="OBS is al actief" AlreadyRunning.Text="OBS is al actief! Tenzij je dit wilde doen, sluit a.u.b. alle reeds draaiende instanties van OBS voor je een nieuwe instantie opstart. Als je OBS hebt ingesteld om naar het systeemvak te minimaliseren, controleer dan of hij daar nog uitgevoerd wordt." -AlreadyRunning.LaunchAnyway="Toch Starten" +AlreadyRunning.LaunchAnyway="Toch starten" ChromeOS.Title="Niet-ondersteund platform" -ChromeOS.Text="OBS lijkt te worden uitgevoerd in een ChromeOS container. Dit platform wordt niet ondersteund" +ChromeOS.Text="OBS lijkt te worden uitgevoerd in een ChromeOS-container; dit platform wordt niet ondersteund" -DockCloseWarning.Title="Dokbaar Venster Sluiten" -DockCloseWarning.Text="Je hebt net een dokbaar venster gesloten. Als je het opnieuw wilt zien, gebruik dan het menu Beeld → Docks in de menubalk." +DockCloseWarning.Title="Dockbaar venster sluiten" +DockCloseWarning.Text="Je hebt net een dockbaar venster gesloten; als je het opnieuw wilt tonen, gebruik dan het menu Beeld → Docks in de menubalk." -ExtraBrowsers="Aangepaste Browser Docks" +ExtraBrowsers="Aangepaste browser-docks" ExtraBrowsers.Info="Voeg docks toe door ze een naam en URL te geven, klik vervolgens op Toepassen of Sluiten om de docks te openen. U kunt op elk moment docks toevoegen of verwijderen." -ExtraBrowsers.DockName="Dock Naam" +ExtraBrowsers.DockName="Dock-naam" Auth.Authing.Title="Authenticeren..." -Auth.Authing.Text="Authenticeren met %1, even geduld a.u.b..." +Auth.Authing.Text="Authenticeren bij %1, even geduld..." Auth.AuthFailure.Title="Authenticatie fout" Auth.AuthFailure.Text="Authenticeren met %1 is mislukt:\n\n%2: %3" -Auth.InvalidScope.Title="Verificatie vereist" +Auth.InvalidScope.Title="Authenticatie vereist" Auth.InvalidScope.Text="De authenticatie vereisten voor %1 zijn gewijzigd. Sommige functies zijn mogelijk niet beschikbaar." Auth.LoadingChannel.Title="Kanaalinformatie laden..." Auth.LoadingChannel.Text="Kanaalinformatie voor %1 laden, even geduld a.u.b..." @@ -121,17 +121,17 @@ Auth.ChannelFailure.Title="Fout bij het laden van kanaal" Auth.ChannelFailure.Text="Fout bij het laden van kanaal informatie voor %1\n\n%2: %3" Auth.Chat="Chat" Auth.StreamInfo="Stream-informatie" -TwitchAuth.Stats="Twitch statistieken" -TwitchAuth.Feed="Twitch activiteitenfeed" -TwitchAuth.TwoFactorFail.Title="Kon stream key niet opvragen" -TwitchAuth.TwoFactorFail.Text="OBS kon geen verbinding maken met uw Twitch account. Zorg ervoor dat er twee-factor authenticatie is ingesteld in uw Twitch beveiligingsinstellingen, omdat dit nodig is om te streamen." -RestreamAuth.Channels="Restream Kanalen" +TwitchAuth.Stats="Twitch-statistieken" +TwitchAuth.Feed="Twitch-activiteitenfeed" +TwitchAuth.TwoFactorFail.Title="Stream-key opvragen niet mogelijk" +TwitchAuth.TwoFactorFail.Text="OBS kon geen verbinding maken met het Twitch-account; zorg ervoor dat er tweestappen-authenticatie ingesteld is in de Twitch-beveiligingsinstellingen, omdat dit vereist is om te kunnen streamen." +RestreamAuth.Channels="Kanalen opnieuw streamen" Copy.Filters="Kopieer Filters" Paste.Filters="Plak filters" -BrowserPanelInit.Title="Browser Opstarten..." -BrowserPanelInit.Text="Browser opstarten, even geduld a.u.b..." +BrowserPanelInit.Title="De browser wordt gestart..." +BrowserPanelInit.Text="De browser wordt gestart, even geduld..." BandwidthTest.Region="Regio" BandwidthTest.Region.US="Verenigde Staten" @@ -139,15 +139,15 @@ BandwidthTest.Region.EU="Europa" BandwidthTest.Region.Asia="Azië" BandwidthTest.Region.Other="Overig" -Basic.AutoConfig="Automatische configuratieassistent" +Basic.AutoConfig="Automatische configuratie-wizard" Basic.AutoConfig.ApplySettings="Instellingen toepassen" Basic.AutoConfig.StartPage="Gebruiksinformatie" -Basic.AutoConfig.StartPage.SubTitle="Waar wil je het programma voor gebruiken?" -Basic.AutoConfig.StartPage.PrioritizeStreaming="Optimaliseren voor streamen, lokaal opnemen is minder belangrijk" -Basic.AutoConfig.StartPage.PrioritizeRecording="Optimaliseren voor lokaal opnemen, ik ga niet streamen" -Basic.AutoConfig.StartPage.PrioritizeVirtualCam="Ik ga alleen de virtuele camera gebruiken" +Basic.AutoConfig.StartPage.SubTitle="Geef aan waarvoor je het programma wilt gebruiken" +Basic.AutoConfig.StartPage.PrioritizeStreaming="Optimaliseren voor streamen, opnemen is minder belangrijk" +Basic.AutoConfig.StartPage.PrioritizeRecording="Optimaliseren voor opnemen, ik ga niet streamen" +Basic.AutoConfig.StartPage.PrioritizeVirtualCam="Ik zal alleen de virtuele camera gebruiken" Basic.AutoConfig.VideoPage="Video-instellingen" -Basic.AutoConfig.VideoPage.SubTitle="Specifieer welke videoinstellingen u wenst te gebruiken" +Basic.AutoConfig.VideoPage.SubTitle="Specifieer welke video-instellingen je wilt gebruiken" Basic.AutoConfig.VideoPage.BaseResolution.UseCurrent="Gebruik huidige (%1x%2)" Basic.AutoConfig.VideoPage.BaseResolution.Display="Beeldscherm %1 (%2x%3)" Basic.AutoConfig.VideoPage.FPS.UseCurrent="Gebruik huidige (%1)" @@ -156,11 +156,12 @@ Basic.AutoConfig.VideoPage.FPS.PreferHighRes="60 of 30, maar geef de voorkeur aa Basic.AutoConfig.VideoPage.CanvasExplanation="Let op: de basisresolutie (canvas) hoeft niet gelijk te zijn als de resolutie waarmee je streamt of opneemt. Je stream/opnameresolutie kan omlaag bijgeschaald worden vanaf de basisresolutie om de belasting op de computer of de benodigde bitrate te verlagen." Basic.AutoConfig.StreamPage="Stream-informatie" Basic.AutoConfig.StreamPage.SubTitle="Voer alstublieft uw stream-informatie in" -Basic.AutoConfig.StreamPage.ConnectAccount="Verbind Account (aanbevolen)" +Basic.AutoConfig.StreamPage.ConnectAccount="Maak verbinding met het account (aanbevolen)" Basic.AutoConfig.StreamPage.DisconnectAccount="Account loskoppelen" Basic.AutoConfig.StreamPage.DisconnectAccount.Confirm.Title="Account loskoppelen?" Basic.AutoConfig.StreamPage.DisconnectAccount.Confirm.Text="Deze wijziging zal onmiddellijk van toepassing zijn. Weet u zeker dat u uw account wilt loskoppelen?" -Basic.AutoConfig.StreamPage.GetStreamKey="Haal streamsleutel op" +Basic.AutoConfig.StreamPage.GetStreamKey="Haal een streamsleutel op" +Basic.AutoConfig.StreamPage.MoreInfo="Meer informatie" Basic.AutoConfig.StreamPage.UseStreamKey="Gebruik Stream Key" Basic.AutoConfig.StreamPage.Service="Dienst" Basic.AutoConfig.StreamPage.Service.ShowAll="Toon alles..." @@ -189,8 +190,8 @@ Basic.AutoConfig.TestPage.Result.StreamingEncoder="Streamingencoder" Basic.AutoConfig.TestPage.Result.RecordingEncoder="Opname-encoder" Basic.AutoConfig.TestPage.Result.Header="Het programma heeft vastgesteld dat deze geschatte instellingen het meest ideaal zijn voor jou:" Basic.AutoConfig.TestPage.Result.Footer="Om deze instellingen te gebruiken, klik op Instellingen Toepassen. Om de configuratieassistent aan te passen, klik op Terug. Om de instellingen handmatig te bepalen, klik op Annuleren en open de instellingen." -Basic.AutoConfig.Info="De automatische configuratiewizard bepaalt de beste instellingen op basis van uw computerspecificaties en de snelheid van de internetverbinding." -Basic.AutoConfig.RunAnytime="Dit kan op elk moment worden uitgevoerd door naar het Tools menu te gaan." +Basic.AutoConfig.Info="De automatische configuratiewizard bepaalt de beste instellingen op basis van de computerspecificaties en de snelheid van de internetverbinding." +Basic.AutoConfig.RunAnytime="Dit kan op elk moment uitgevoerd worden door naar het Tools-menu te gaan." Basic.Stats="Statistieken" Basic.Stats.CPUUsage="Processorgebruik" @@ -221,54 +222,54 @@ Updater.Text="Er is een update beschikbaar:" Updater.UpdateNow="Nu updaten" Updater.RemindMeLater="Herinner mij later" Updater.Skip="Sla deze versie over" -Updater.Running.Title="Programma actief" -Updater.Running.Text="Er is momenteel een uitvoer actief, stop alle actieve uitvoer voor je probeert te updaten" +Updater.Running.Title="Programma op dit moment actief" +Updater.Running.Text="Er is momenteel uitvoer actief; stop alle actieve uitvoer voordat je probeert te updaten" Updater.NoUpdatesAvailable.Title="Geen updates beschikbaar" Updater.NoUpdatesAvailable.Text="Er zijn momenteel geen updates beschikbaar" Updater.FailedToLaunch="Starten van updater is mislukt" -Updater.GameCaptureActive.Title="Game capture actief" -Updater.GameCaptureActive.Text="Er is momenteel een game capture hook in gebruik. Sluit alle games/programma's af die opgenomen worden (of herstart Windows) en probeer het opnieuw." +Updater.GameCaptureActive.Title="Game-capture actief" +Updater.GameCaptureActive.Text="De game-capture-hook-bibliotheek in momenteel in gebruik; sluit alle games/programma's af die opgenomen worden (of herstart Windows) en probeer het nog eens." -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." -QuickTransitions.DuplicateScene="Scène Dupliceren" +QuickTransitions.SwapScenes="Voorvertonings-/uitvoerscènes verwisselen na overgang" +QuickTransitions.SwapScenesTT="Verwisselt de voorvertonings- en uitvoercènes na een overgang (als de originele uitvoerscène nog bestaat.)\nDit zal veranderingen niet ongedaan maken die misschien zijn gemaakt aan de originele uitvoerscène." +QuickTransitions.DuplicateScene="Scène dupliceren" QuickTransitions.DuplicateSceneTT="Wanneer je dezelfde scene bewerkt, staat dit toe om de transformatie/zichtbaarheid van de bronnen aan te passen zonder de uitvoerscène aan te passen.\nOm eigenschappen van bronnen aan te passen zonder de uitvoerscène aan te passen, schakel 'Bronnen Dupliceren' in.\nHet veranderen van deze waarde zal de huidige uitvoerscène resetten (als deze nog bestaat)." -QuickTransitions.EditProperties="Bronnen Dupliceren" +QuickTransitions.EditProperties="Bronnen dupliceren" QuickTransitions.EditPropertiesTT="Wanneer je dezelfde scène bewerkt, staat dit het bewerken van eigenschappen van bronnen toe zonder de uitvoerscène aan te passen.\nDit kan alleen worden gebruikt als 'Scène Dupliceren' is ingeschakeld.\nSommige bronnen (zoals opname- of mediabronnen) ondersteunen dit niet en kunnen niet onafhankelijk worden bewerkt.\nHet veranderen van deze waarden zal de huidige scène resetten (als deze nog bestaat).\n\nWaarschuwing: Omdat bronnen zullen worden gedupliceerd kan dit extra systeem of video rekenkracht verbruiken." QuickTransitions.HotkeyName="Snelle overgang: %1" Basic.AddTransition="Instelbare overgang toevoegen" Basic.RemoveTransition="Instelbare overgang verwijderen" -Basic.TransitionProperties="Overgang-eigenschappen" +Basic.TransitionProperties="Overgangseigenschappen" Basic.SceneTransitions="Scène-overgangen" Basic.TransitionDuration="Duur" Basic.TogglePreviewProgramMode="Studiomodus" -TransitionNameDlg.Text="Voer a.u.b. de naam van de transitie in" +TransitionNameDlg.Text="Voer de naam van de transitie in" TransitionNameDlg.Title="Naam van de overgang" TitleBar.Profile="Profiel" TitleBar.Scenes="Scènes" -NameExists.Title="Naam bestaat al" +NameExists.Title="De naam bestaat al" NameExists.Text="De naam is al in gebruik." -NoNameEntered.Title="Voer a.u.b. een geldige naam in" +NoNameEntered.Title="Voer een geldige naam in" NoNameEntered.Text="Je kunt geen lege namen gebruiken." -ConfirmStart.Title="Start de Stream?" -ConfirmStart.Text="Weet je zeker dat je de stream wil starten?" +ConfirmStart.Title="De stream starten?" +ConfirmStart.Text="Weet je zeker dat je de stream wilt starten?" -ConfirmStop.Title="Stop de Stream?" -ConfirmStop.Text="Weet je zeker dat je de stream wil stoppen?" +ConfirmStop.Title="De stream stoppen?" +ConfirmStop.Text="Weet je zeker dat je de stream wilt stoppen?" -ConfirmStopRecord.Title="Opname Stoppen?" -ConfirmStopRecord.Text="Bent u zeker dat u de opname wilt stoppen?" +ConfirmStopRecord.Title="Opnemen stoppen?" +ConfirmStopRecord.Text="Weet je zeker dat je het opnemen wilt stoppen?" -ConfirmBWTest.Title="Bandbreedte test starten?" +ConfirmBWTest.Title="Bandbreedte-test starten?" ConfirmBWTest.Text="U heeft OBS geconfigureerd in bandbreedte test modus. Deze modus maakt het mogelijk om netwerk te testen zonder live te gaan. Zodra u klaar bent met testen, moet u deze uitschakelen om de kijkers in staat te stellen uw stream te zien.\n\nWilt u doorgaan?" -ConfirmExit.Title="OBS Afsluiten?" +ConfirmExit.Title="OBS afsluiten?" ConfirmExit.Text="OBS is momenteel actief. Alle streams/opnames zullen worden afgebroken. Weet je zeker dat je wil afsluiten?" ConfirmRemove.Title="Bevestig het verwijderen" @@ -281,7 +282,7 @@ Output.StartReplayFailed="Het starten van de replay buffer is mislukt" Output.StartFailedGeneric="Het starten van de uitvoer is mislukt. Controleer de logbestanden voor meer informatie.\n\nLet op: Als je gebruik maakt van de NVENC of AMD encoders, controleer of de drivers up to date zijn." Output.ReplayBuffer.PauseWarning.Title="Herhalingen kunnen niet worden opgeslagen tijdens het pauzeren" -Output.ReplayBuffer.PauseWarning.Text="Waarschuwing: Herhalingen kunnen niet worden opgeslagen tijdens het pauzeren van de opname." +Output.ReplayBuffer.PauseWarning.Text="Waarschuwing: herhalingen kunnen niet worden opgeslagen als opnemen gepauzeerd is." Output.ConnectFail.Title="Kan geen verbinding maken" Output.ConnectFail.BadPath="Ongeldig pad of verbindings-url. Controleer a.u.b. of je instellingen geldig zijn." @@ -296,44 +297,44 @@ Output.StreamEncodeError.Msg="Er is een coderingsfout opgetreden tijdens het str Output.RecordFail.Title="Kon de opname niet starten" Output.RecordFail.Unsupported="Het outputformaat wordt niet ondersteund, of ondersteunt niet meer dan een audiotrack. Controleer je instellingen en probeer het opnieuw." Output.RecordNoSpace.Title="Onvoldoende schijfruimte" -Output.RecordNoSpace.Msg="Er is niet voldoende schijfruimte om door te gaan met opnemen." +Output.RecordNoSpace.Msg="Er is onvoldoende schijfruimte om door te gaan met opnemen." Output.RecordError.Title="Opnamefout" Output.RecordError.Msg="Er is een onbekende fout opgetreden tijdens het opnemen." Output.RecordError.EncodeErrorMsg="Er is een coderingsfout opgetreden tijdens het opnemen." -Output.BadPath.Title="Ongeldig Bestandspad" -Output.BadPath.Text="Het geconfigureerde bestandsuitvoerpad is ongeldig. Controleer a.u.b. je instellingen om te bevestigen dat er een geldig bestandspad is ingesteld." +Output.BadPath.Title="Ongeldig bestandspad" +Output.BadPath.Text="Het geconfigureerde bestandsuitvoerpad is ongeldig; controleer de instellingen om er zeker van te zijn dat er een geldig bestandspad ingesteld is." -LogReturnDialog="Log succesvol geüpload" -LogReturnDialog.Description="Uw logbestand is geüpload. U kunt nu de URL delen voor debugging of ondersteuningsdoeleinden." -LogReturnDialog.Description.Crash="Uw crashrapport is geüpload. U kunt nu de URL delen voor debugging doeleinden." -LogReturnDialog.CopyURL="URL kopiëren" +LogReturnDialog="Log-upload gelukt" +LogReturnDialog.Description="Het logbestand is geüpload; je kunt nu de URL delen voor foutopsporings- of supportdoeleinden." +LogReturnDialog.Description.Crash="Het crashrapport is geüpload; je kunt nu de URL delen voor foutopsporingsdoeleinden." +LogReturnDialog.CopyURL="Kopieer de URL" LogReturnDialog.AnalyzeURL="Analyseren" LogReturnDialog.ErrorUploadingLog="Fout bij het uploaden van het logbestand" Remux.SourceFile="OBS Opname" Remux.TargetFile="Doelbestand" Remux.Remux="Remuxen" -Remux.Stop="Stop remuxen" +Remux.Stop="Stop met remuxen" Remux.ClearFinished="Verwijder voltooide items" -Remux.ClearAll="Alle items wissen" -Remux.OBSRecording="OBS Opname" +Remux.ClearAll="Verwijder alle items" +Remux.OBSRecording="OBS-opnemen" Remux.FinishedTitle="Remuxen voltooid" Remux.Finished="Opname geremuxt" Remux.FinishedError="Opname geremuxt, maar het bestand zou incompleet kunnen zijn" -Remux.SelectRecording="Kies OBS Opname..." -Remux.SelectTarget="Selecteer doelbestand..." +Remux.SelectRecording="Selecteer OBS-opnemen..." +Remux.SelectTarget="Selecteer het doelbestand..." Remux.FileExistsTitle="Doelbestanden bestaan al" -Remux.FileExists="Het volgende doelbestanden bestaan al. Wil je deze vervangen?" +Remux.FileExists="De volgende doelbestanden bestaan al; wil je ze vervangen?" Remux.ExitUnfinishedTitle="Remuxen is bezig" -Remux.ExitUnfinished="Het remuxen is nog niet compleet, als je nu stopt kan het doelbestand onbruikbaar worden.\nWeet je zeker dat je wil stoppen met remuxen?" -Remux.HelpText="Drop bestanden in dit scherm om te remuxen, of selecteer een leeg \"OBS Opname\" cell om te zoeken voor een bestand." +Remux.ExitUnfinished="Het remuxen is nog niet afgerond; als je nu stopt kan het doelbestand onbruikbaar worden.\nWeet je zeker dat je wil stoppen met remuxen?" +Remux.HelpText="Laat bestanden in dit scherm vallen om ze te remuxen, of selecteer een lege 'OBS-opname'-cel om te zoeken naar een bestand." -UpdateAvailable="Nieuwe Update Beschikbaar" -UpdateAvailable.Text="Versie %1.%2.%3 is nu beschikbaar. Klik hier om te downloaden" +UpdateAvailable="Nieuwe update beschikbaar" +UpdateAvailable.Text="Versie %1.%2.%3 is nu beschikbaar; klik hier om hem te downloaden" -Basic.DesktopDevice1="Desktop Audio" -Basic.DesktopDevice2="Desktop Audio 2" +Basic.DesktopDevice1="Desktop-audio" +Basic.DesktopDevice2="Desktop-audio 2" Basic.AuxDevice1="Mic/Aux" Basic.AuxDevice2="Mic/Aux 2" Basic.AuxDevice3="Mic/Aux 3" @@ -353,35 +354,36 @@ ScaleFiltering.Bicubic="Bicubic" ScaleFiltering.Lanczos="Lanczos" ScaleFiltering.Area="Gebied" -Deinterlacing="Deinterlacing" -Deinterlacing.Discard="Verwerpen" +Deinterlacing="Deïnterlacen" +Deinterlacing.Discard="Negeren" Deinterlacing.Retro="Retro" -Deinterlacing.Blend="Blend" -Deinterlacing.Blend2x="Blend 2x" -Deinterlacing.Linear="Linear" -Deinterlacing.Linear2x="Linear 2x" +Deinterlacing.Blend="Mengen" +Deinterlacing.Blend2x="Mengen 2x" +Deinterlacing.Linear="Lineair" +Deinterlacing.Linear2x="Lineair 2x" Deinterlacing.Yadif="Yadif" Deinterlacing.Yadif2x="Yadif 2x" -Deinterlacing.TopFieldFirst="Bovenste Veld Eerst" -Deinterlacing.BottomFieldFirst="Onderste Veld Eerst" +Deinterlacing.TopFieldFirst="Bovenste veld eerst" +Deinterlacing.BottomFieldFirst="Onderste veld eerst" -VolControl.SliderUnmuted="Volumeregelaar voor '%1': %2" -VolControl.SliderMuted="Volumeregelaar voor '%1': %2 (momenteel gemute)" -VolControl.Mute="Mute '%1'" +VolControl.SliderUnmuted="Volumeregelaar voor '%1':" +VolControl.SliderMuted="Volumeregelaar voor '%1': (momenteel gedempt)" +VolControl.Mute="'%1' dempen" VolControl.Properties="Eigenschappen van '%1'" -Basic.Main.AddSceneDlg.Title="Scène Toevoegen" -Basic.Main.AddSceneDlg.Text="Voer a.u.b. de naam van de scène in" +Basic.Main.AddSceneDlg.Title="Voeg scène toe" +Basic.Main.AddSceneDlg.Text="Voer de naam van de scène in" Basic.Main.DefaultSceneName.Text="Scène %1" Basic.Main.AddSceneCollection.Title="Scèneverzameling toevoegen" Basic.Main.AddSceneCollection.Text="Voer de naam van de scèneverzameling in" -Basic.Main.RenameSceneCollection.Title="Scèneverzameling Hernoemen" +Basic.Main.RenameSceneCollection.Title="Hernoem de scèneverzameling" -AddProfile.Title="Profiel Toevoegen" +AddProfile.Title="Voeg profiel toe" AddProfile.Text="Voer de naam van het profiel in" +AddProfile.WizardCheckbox="Toon automatische configuratie-wizard" RenameProfile.Title="Profiel hernoemen" @@ -396,29 +398,34 @@ Basic.SourceSelect.CreateNew="Nieuwe maken" Basic.SourceSelect.AddExisting="Bestaande toevoegen" Basic.SourceSelect.AddVisible="Maak bron zichtbaar" +Basic.Main.Sources.Visibility="Zichtbaarheid" +Basic.Main.Sources.VisibilityDescription="Bepaalt de zichtbaarheid van '%1' op het canvas" +Basic.Main.Sources.Lock="Vergrendel" +Basic.Main.Sources.LockDescription="Vergrendelt de positie en schaal van '%1' op het canvas" + Basic.PropertiesWindow="Eigenschappen van '%1'" Basic.PropertiesWindow.AutoSelectFormat="%1 (automatisch geselecteerd: %2)" Basic.PropertiesWindow.SelectColor="Selecteer kleur" -Basic.PropertiesWindow.SelectFont="Selecteer lettertype" +Basic.PropertiesWindow.SelectFont="Selecteer een lettertype" Basic.PropertiesWindow.ConfirmTitle="Instellingen Aangepast" Basic.PropertiesWindow.Confirm="Er zijn onopgeslagen aanpassingen. Wil je deze bewaren?" Basic.PropertiesWindow.NoProperties="Geen eigenschappen beschikbaar" -Basic.PropertiesWindow.AddFiles="Bestanden Toevoegen" -Basic.PropertiesWindow.AddDir="Map Toevoegen" -Basic.PropertiesWindow.AddURL="Pad/URL Toevoegen" -Basic.PropertiesWindow.AddEditableListDir="Voeg map toe aan '%1'" +Basic.PropertiesWindow.AddFiles="Voeg bestanden toe" +Basic.PropertiesWindow.AddDir="Voeg de directory toe" +Basic.PropertiesWindow.AddURL="Voeg pad/URL toe" +Basic.PropertiesWindow.AddEditableListDir="Voeg een directory toe aan '%1'" Basic.PropertiesWindow.AddEditableListFiles="Voeg bestanden toe aan '%1'" -Basic.PropertiesWindow.AddEditableListEntry="Voeg toe aan '%1'" -Basic.PropertiesWindow.EditEditableListEntry="Verwijder van '%1'" +Basic.PropertiesWindow.AddEditableListEntry="Voeg invoer toe aan '%1'" +Basic.PropertiesWindow.EditEditableListEntry="Bewerk de invoer van '%1'" Basic.PropertiesView.FPS.Simple="Simpele FPS Waarden" -Basic.PropertiesView.FPS.Rational="Rationele FPS Waarden" +Basic.PropertiesView.FPS.Rational="Rationale FPS-waarden" Basic.PropertiesView.FPS.ValidFPSRanges="Geldige FPS-bereiken:" Basic.InteractionWindow="Interactie met '%1'" Basic.StatusBar.Reconnecting="Verbinding verbroken, opnieuw verbinden over %2 second(en) (poging %1)" -Basic.StatusBar.AttemptingReconnect="Opnieuw verbinden... (poging %1)" +Basic.StatusBar.AttemptingReconnect="Poging opnieuw te verbinden... (poging %1)" Basic.StatusBar.ReconnectSuccessful="Opnieuw verbinden gelukt" Basic.StatusBar.Delay="Vertraging (%1 sec)" Basic.StatusBar.DelayStartingIn="Vertraging (start over %1 sec)" @@ -426,9 +433,9 @@ Basic.StatusBar.DelayStoppingIn="Vertraging (stopt over %1 sec)" Basic.StatusBar.DelayStartingStoppingIn="Vertraging (stopt over %1 sec, start over %2 sec)" Basic.Filters="Filters" -Basic.Filters.AsyncFilters="Audio/Video Filters" -Basic.Filters.AudioFilters="Audio Filters" -Basic.Filters.EffectFilters="Effect Filters" +Basic.Filters.AsyncFilters="Audio-/video-filters" +Basic.Filters.AudioFilters="Audio-filters" +Basic.Filters.EffectFilters="Effect-filters" Basic.Filters.Title="Filters voor '%1'" Basic.Filters.AddFilter.Title="Filternaam" Basic.Filters.AddFilter.Text="Geef een naam voor de filter" @@ -448,104 +455,104 @@ Basic.TransformWindow.Alignment.TopCenter="Boven" Basic.TransformWindow.Alignment.TopRight="Rechtsboven" Basic.TransformWindow.Alignment.CenterLeft="Links" Basic.TransformWindow.Alignment.Center="Midden" -Basic.TransformWindow.Alignment.CenterRight="Rechts" +Basic.TransformWindow.Alignment.CenterRight="Midden-rechts" Basic.TransformWindow.Alignment.BottomLeft="Linksonder" -Basic.TransformWindow.Alignment.BottomCenter="Onder" +Basic.TransformWindow.Alignment.BottomCenter="Middenonder" Basic.TransformWindow.Alignment.BottomRight="Rechtsonder" Basic.TransformWindow.BoundsType.None="Geen grenzen" -Basic.TransformWindow.BoundsType.MaxOnly="Alleen maximale grootte" +Basic.TransformWindow.BoundsType.MaxOnly="Alleen maximumgrootte" Basic.TransformWindow.BoundsType.ScaleInner="Schaal naar binnenste grenzen" Basic.TransformWindow.BoundsType.ScaleOuter="Schaal naar buitenste grenzen" -Basic.TransformWindow.BoundsType.ScaleToWidth="Schaal naar breedte van grenzen" -Basic.TransformWindow.BoundsType.ScaleToHeight="Schaal naar hoogte van grenzen" -Basic.TransformWindow.BoundsType.Stretch="Uitrekken naar grenzen" +Basic.TransformWindow.BoundsType.ScaleToWidth="Schaal naar de breedte van de grenzen" +Basic.TransformWindow.BoundsType.ScaleToHeight="Schaal naar de hoogte van de grenzen" +Basic.TransformWindow.BoundsType.Stretch="Uitrekken naar de grenzen" -Basic.Main.AddSourceHelp.Title="Kan bron niet toevoegen" -Basic.Main.AddSourceHelp.Text="Je moet ten minste 1 scène hebben om een bron toe te voegen." +Basic.Main.AddSourceHelp.Title="Bron kan niet toegevoegd worden" +Basic.Main.AddSourceHelp.Text="Je moet ten minste één scène hebben om een bron toe te kunnen voegen." Basic.Main.Scenes="Scènes" Basic.Main.Sources="Bronnen" -Basic.Main.Controls="Controls" +Basic.Main.Controls="Bedieningselementen" Basic.Main.Connecting="Verbinden..." -Basic.Main.StartRecording="Opname Starten" -Basic.Main.StartReplayBuffer="Start Replay Buffer" -Basic.Main.SaveReplay="Replay Opslaan" -Basic.Main.StartStreaming="Stream Starten" -Basic.Main.StartVirtualCam="Virtuele camera starten" -Basic.Main.StopRecording="Opname Stoppen" -Basic.Main.PauseRecording="Opname pauzeren" -Basic.Main.UnpauseRecording="Opname vervolgen" -Basic.Main.StoppingRecording="Opname Stoppen..." -Basic.Main.StopReplayBuffer="Stop Replay Buffer" -Basic.Main.StoppingReplayBuffer="Replay Buffer aan het stoppen..." -Basic.Main.StopStreaming="Stream Stoppen" -Basic.Main.StoppingStreaming="Stream Stoppen..." -Basic.Main.ForceStopStreaming="Stop Stream (vertraging negeren)" -Basic.Main.ShowContextBar="Toon bronwerkbalk" -Basic.Main.HideContextBar="Verberg bronwerkbalk" -Basic.Main.StopVirtualCam="Virtuele camera stoppen" +Basic.Main.StartRecording="Start het opnemen" +Basic.Main.StartReplayBuffer="Start de replaybuffer" +Basic.Main.SaveReplay="Replay opslaan" +Basic.Main.StartStreaming="Streamen starten" +Basic.Main.StartVirtualCam="Start de virtuele camera" +Basic.Main.StopRecording="Stop met opnemen" +Basic.Main.PauseRecording="Pauzeer de opname" +Basic.Main.UnpauseRecording="Vervolg de opname" +Basic.Main.StoppingRecording="De opname stoppen..." +Basic.Main.StopReplayBuffer="De replaybuffer stoppen" +Basic.Main.StoppingReplayBuffer="De replaybuffer aan het stoppen..." +Basic.Main.StopStreaming="Streamen stoppen" +Basic.Main.StoppingStreaming="De stream stoppen..." +Basic.Main.ForceStopStreaming="Stop het streamen (vertraging negeren)" +Basic.Main.ShowContextBar="Toon de bron-taakbalk" +Basic.Main.HideContextBar="Verberg de brontaakbalk" +Basic.Main.StopVirtualCam="Stop de virtuele camera" Basic.Main.Group="Groep %1" -Basic.Main.GroupItems="Groepeer geselecteerde items" +Basic.Main.GroupItems="Groepeer de geselecteerde items" Basic.Main.Ungroup="Degroeperen" -Basic.Main.GridMode="Rasterweergave" -Basic.Main.ListMode="Lijstweergave" +Basic.Main.GridMode="Rastermodus" +Basic.Main.ListMode="Lijstmodus" -Basic.MainMenu.File="Bestand (&F)" +Basic.MainMenu.File="&Bestand" Basic.MainMenu.File.Export="&Exporteren" Basic.MainMenu.File.Import="&Importeren" -Basic.MainMenu.File.ShowRecordings="Opnames Weergeven (&R)" -Basic.MainMenu.File.Remux="Re&mux Opnames" +Basic.MainMenu.File.ShowRecordings="Toon de &opnames" +Basic.MainMenu.File.Remux="Re&mux de opnames" Basic.MainMenu.File.Settings="In&stellingen" -Basic.MainMenu.File.ShowSettingsFolder="Instellingenmap Openen" -Basic.MainMenu.File.ShowProfileFolder="Profielmap Openen" -Basic.MainMenu.AlwaysOnTop="&Altijd op voorgrond" -Basic.MainMenu.File.Exit="Afsluiten (&X)" +Basic.MainMenu.File.ShowSettingsFolder="Toon de instellingenmap" +Basic.MainMenu.File.ShowProfileFolder="Toon de profielmap" +Basic.MainMenu.AlwaysOnTop="&Altijd op de voorgrond" +Basic.MainMenu.File.Exit="&Afsluiten" -Basic.MainMenu.Edit="B&ewerken" -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.Scale="Preview &schalen" -Basic.MainMenu.Edit.Scale.Window="Schaal naar venster" +Basic.MainMenu.Edit="&Bewerken" +Basic.MainMenu.Edit.Undo="&Ongedaan maken" +Basic.MainMenu.Edit.Redo="&Opnieuw" +Basic.MainMenu.Edit.UndoAction="$1 ongedaan &maken" +Basic.MainMenu.Edit.RedoAction="$1 opnieuw &toepassen" +Basic.MainMenu.Edit.LockPreview="Voorvertoning vergrende&len" +Basic.MainMenu.Edit.Scale="Voorvertoning &schalen" +Basic.MainMenu.Edit.Scale.Window="Schaal naar het venster" Basic.MainMenu.Edit.Scale.Canvas="Canvas (%1x%2)" Basic.MainMenu.Edit.Scale.Output="Uitvoer (%1x%2)" Basic.MainMenu.Edit.Transform="&Transformeren" -Basic.MainMenu.Edit.Transform.EditTransform="Transformatie bewerken... (&E)" -Basic.MainMenu.Edit.Transform.CopyTransform="Kopieer transformatie" -Basic.MainMenu.Edit.Transform.PasteTransform="Plak transformatie" -Basic.MainMenu.Edit.Transform.ResetTransform="Transformatie herstellen (&R)" -Basic.MainMenu.Edit.Transform.Rotate90CW="Rechtsom kantelen" -Basic.MainMenu.Edit.Transform.Rotate90CCW="Linksom kantelen" -Basic.MainMenu.Edit.Transform.Rotate180="180 graden draaien" -Basic.MainMenu.Edit.Transform.FlipHorizontal="&Horizontaal Spiegelen" -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.Transform.EditTransform="Transformatie &bewerken..." +Basic.MainMenu.Edit.Transform.CopyTransform="Kopieer de transformatie" +Basic.MainMenu.Edit.Transform.PasteTransform="Plak de transformatie" +Basic.MainMenu.Edit.Transform.ResetTransform="&Reset de transformatie" +Basic.MainMenu.Edit.Transform.Rotate90CW="Draai 90º rechtsom" +Basic.MainMenu.Edit.Transform.Rotate90CCW="Draai 90º linksom" +Basic.MainMenu.Edit.Transform.Rotate180="Draai 180º" +Basic.MainMenu.Edit.Transform.FlipHorizontal="&Horizontaal spiegelen" +Basic.MainMenu.Edit.Transform.FlipVertical="&Verticaal spiegelen" +Basic.MainMenu.Edit.Transform.FitToScreen="Aan het &scherm aanpassen" +Basic.MainMenu.Edit.Transform.StretchToScreen="Uitrekken naar het &scherm" +Basic.MainMenu.Edit.Transform.CenterToScreen="&Centeren op het scherm" Basic.MainMenu.Edit.Transform.VerticalCenter="Verticaal centreren" Basic.MainMenu.Edit.Transform.HorizontalCenter="Horizontaal centreren" 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)" -Basic.MainMenu.Edit.Order.MoveToBottom="Naar Onderen Schuiven (&B)" -Basic.MainMenu.Edit.AdvAudio="Geavanceerde &Audioinstellingen" +Basic.MainMenu.Edit.Order.MoveUp="Omhoog &verplaatsen" +Basic.MainMenu.Edit.Order.MoveDown="Omlaag ver&plaatsen" +Basic.MainMenu.Edit.Order.MoveToTop="Naar boven verplaa&tsen" +Basic.MainMenu.Edit.Order.MoveToBottom="Naar de onderkant &verplaatsen" +Basic.MainMenu.Edit.AdvAudio="Geavanceerde &audio-eigenschappen" -Basic.MainMenu.View="Beeld (&V)" -Basic.MainMenu.View.Toolbars="Werkbalken (&T)" +Basic.MainMenu.View="Beel&d" +Basic.MainMenu.View.Toolbars="&Taakbalken" Basic.MainMenu.View.Docks="Docks" -Basic.MainMenu.View.Docks.ResetUI="Herstel UI" -Basic.MainMenu.View.Docks.LockUI="Zet UI Vast" -Basic.MainMenu.View.Docks.CustomBrowserDocks="Aangepaste Browser Docks..." -Basic.MainMenu.View.ListboxToolbars="Scène/Bronlijst knoppen" -Basic.MainMenu.View.ContextBar="Bron werkbalk" +Basic.MainMenu.View.Docks.ResetUI="Reset de UI" +Basic.MainMenu.View.Docks.LockUI="Vergrendel de UI" +Basic.MainMenu.View.Docks.CustomBrowserDocks="Aangepaste browser-docks..." +Basic.MainMenu.View.ListboxToolbars="Scène-/bronlijst-knoppen" +Basic.MainMenu.View.ContextBar="Bron-taakbalk" Basic.MainMenu.View.SceneTransitions="S&cène-overgangen" -Basic.MainMenu.View.SourceIcons="Bron &iconen" +Basic.MainMenu.View.SourceIcons="Bron-&iconen" Basic.MainMenu.View.StatusBar="&Statusbalk" -Basic.MainMenu.View.Fullscreen.Interface="Volledig scherm" +Basic.MainMenu.View.Fullscreen.Interface="Volledig scherminterface" Basic.MainMenu.SceneCollection="&Scèneverzameling" Basic.MainMenu.Profile="&Profiel" @@ -558,54 +565,54 @@ Basic.MainMenu.SceneCollection.Exists="De scèneverzameling bestaat al" Basic.MainMenu.Tools="&Tools" -Basic.MainMenu.Help="&Help" +Basic.MainMenu.Help="&Hulp" Basic.MainMenu.Help.HelpPortal="Help-&portal" -Basic.MainMenu.Help.Website="&Website Bezoeken" +Basic.MainMenu.Help.Website="Ga naar de &website" Basic.MainMenu.Help.Discord="Word lid van onze &Discord-server" Basic.MainMenu.Help.Logs="&Logbestanden" -Basic.MainMenu.Help.Logs.ShowLogs="Logbe&standen Weergeven" -Basic.MainMenu.Help.Logs.UploadCurrentLog="Upload Huidige Logbestand (&C)" -Basic.MainMenu.Help.Logs.UploadLastLog="Upload &Laatste Logbestand" -Basic.MainMenu.Help.Logs.ViewCurrentLog="Toon Huidige Logbestand (&V)" -Basic.MainMenu.Help.CheckForUpdates="Controleer Op Updates" -Basic.MainMenu.Help.CrashLogs="Fouten&rapport" -Basic.MainMenu.Help.CrashLogs.ShowLogs="Toon crashrapporten (&S)" -Basic.MainMenu.Help.CrashLogs.UploadLastLog="Upload &laatste crash rapport" -Basic.MainMenu.Help.About="Over (&A)" +Basic.MainMenu.Help.Logs.ShowLogs="Toon logbe&standen" +Basic.MainMenu.Help.Logs.UploadCurrentLog="Upload het &huidige logbestand" +Basic.MainMenu.Help.Logs.UploadLastLog="Upload het &laatste logbestand" +Basic.MainMenu.Help.Logs.ViewCurrentLog="&Bekijk het huidige logbestand" +Basic.MainMenu.Help.CheckForUpdates="Controleer op updates" +Basic.MainMenu.Help.CrashLogs="Crash-&rapporten" +Basic.MainMenu.Help.CrashLogs.ShowLogs="Toon cra&shrapporten" +Basic.MainMenu.Help.CrashLogs.UploadLastLog="Upload het &laatste crashrapport" +Basic.MainMenu.Help.About="&Over" -Basic.Settings.ProgramRestart="Het programma moet opnieuw worden opgestart om deze instellingen te activeren." -Basic.Settings.ConfirmTitle="Wijzigingen Bevestigen" -Basic.Settings.Confirm="Je hebt onopgeslagen wijzigingen. Wijzigingen opslaan?" +Basic.Settings.ProgramRestart="Het programma moet opnieuw worden opgestart om deze instellingen effectief te maken." +Basic.Settings.ConfirmTitle="Bevestig de wijzigingen" +Basic.Settings.Confirm="Er zijn niet-opgeslagen wijzigingen; wijzigingen opslaan?" Basic.Settings.General="Algemeen" Basic.Settings.General.Theme="Thema" Basic.Settings.General.Language="Taal" -Basic.Settings.General.EnableAutoUpdates="Automatisch controleren op updates tijdens het opstarten" -Basic.Settings.General.OpenStatsOnStartup="Open statistieken bij het opstarten" -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.WarnBeforeStoppingRecord="Laat bevestigingsvenster zien bij het stoppen van opnames" -Basic.Settings.General.Projectors="Projectoren" +Basic.Settings.General.EnableAutoUpdates="Automatisch op updates controleren tijdens het opstarten" +Basic.Settings.General.OpenStatsOnStartup="Open het statistiekenvenster tijdens het opstarten" +Basic.Settings.General.WarnBeforeStartingStream="Toon het bevestigingsvenster bij het starten van streams" +Basic.Settings.General.WarnBeforeStoppingStream="Toon het bevestigingsvenster bij het stoppen van streams" +Basic.Settings.General.WarnBeforeStoppingRecord="Toon het bevestigingsvenster bij het stoppen van de opname" +Basic.Settings.General.Projectors="Projectors" 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" -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.ReplayBufferWhileStreaming="Replay buffer tegelijk starten met stream" -Basic.Settings.General.KeepReplayBufferStreamStops="Replay buffer actief houden als stream stopt" +Basic.Settings.General.ProjectorAlwaysOnTop="Houd projectors altijd op de voorgrond" +Basic.Settings.General.Snapping="Bronuitlijning vastklikken" +Basic.Settings.General.ScreenSnapping="Klik bronnen vast aan de rand van het scherm" +Basic.Settings.General.CenterSnapping="Klik bronnen vast aan het horizontale en verticale midden" +Basic.Settings.General.SourceSnapping="Klik bronnen vast aan andere bronnen" +Basic.Settings.General.SnapDistance="Vastklik-gevoeligheid" +Basic.Settings.General.RecordWhenStreaming="Automatisch opnemen tijdens het streamen" +Basic.Settings.General.KeepRecordingWhenStreamStops="Blijf opnemen als de stream stopt" +Basic.Settings.General.ReplayBufferWhileStreaming="Start de replaybuffer automatisch tijdens het streamen" +Basic.Settings.General.KeepReplayBufferStreamStops="Houd de replaybuffer actief als de stream stopt" Basic.Settings.General.SysTray="Systeemvak" Basic.Settings.General.SysTrayWhenStarted="Naar systeemvak minimaliseren bij opstarten" -Basic.Settings.General.SystemTrayHideMinimize="Altijd minimaliseren naar het systeemvak in plaats van de taakbalk" +Basic.Settings.General.SystemTrayHideMinimize="Altijd minimaliseren naar het systeemvak in plaats van naar de taakbalk" Basic.Settings.General.SaveProjectors="Projectors opslaan bij afsluiten" -Basic.Settings.General.Preview="Preview" +Basic.Settings.General.Preview="Voorvertoning" Basic.Settings.General.OverflowHidden="Overloop verbergen" Basic.Settings.General.OverflowAlwaysVisible="Overloop altijd zichtbaar" -Basic.Settings.General.OverflowSelectionHidden="Overloop weergeven, zelfs wanneer bron onzichtbaar is" -Basic.Settings.General.Importers="Importeurs" +Basic.Settings.General.OverflowSelectionHidden="Overloop weergeven, zelfs als de bron onzichtbaar is" +Basic.Settings.General.Importers="Importeerders" Basic.Settings.General.AutomaticCollectionSearch="Zoek bekende locaties voor scèneverzamelingen bij het importeren" Basic.Settings.General.SwitchOnDoubleClick="Ga over naar scène bij dubbelklik" Basic.Settings.General.StudioPortraitLayout="Portret/verticale layout inschakelen" @@ -622,7 +629,7 @@ Basic.Settings.General.MultiviewLayout.Vertical.Right="Verticaal, rechts (8 scè Basic.Settings.General.MultiviewLayout.Horizontal.Extended.Top="Horizontaal, boven (24 scènes)" Basic.Settings.Stream="Stream" -Basic.Settings.Stream.StreamType="Stream Type" +Basic.Settings.Stream.StreamType="Stream-type" Basic.Settings.Stream.Custom.UseAuthentication="Gebruik authenticatie" Basic.Settings.Stream.Custom.Username="Gebruikersnaam" Basic.Settings.Stream.Custom.Password="Wachtwoord" @@ -630,18 +637,24 @@ Basic.Settings.Stream.BandwidthTestMode="Bandbreedte testmodus inschakelen" Basic.Settings.Stream.TTVAddon="Twitch Chat toevoegingen" Basic.Settings.Stream.TTVAddon.None="Geen" Basic.Settings.Stream.TTVAddon.Both="BeterTTV en FrankerFaceZ" -Basic.Settings.Stream.MissingSettingAlert="Ontbrekende Stream Installatie" +Basic.Settings.Stream.MissingSettingAlert="Ontbrekende stream-configuratie" Basic.Settings.Stream.StreamSettingsWarning="Instellingen openen" -Basic.Settings.Stream.MissingUrlAndApiKey="URL en streamsleutel ontbreken.\n\nOpen instellingen om de URL en streamsleutel in het 'stream' tabblad in te voeren." -Basic.Settings.Stream.MissingUrl="Stream URL ontbreekt.\n\nOpen instellingen om de URL in te voeren in het 'Stream' tabblad." -Basic.Settings.Stream.MissingStreamKey="Stream-sleutel ontbreekt.\n\nOpen instellingen om de stream-sleutel in te voeren in het 'Stream' tabblad." +Basic.Settings.Stream.MissingUrlAndApiKey="URL en streamsleutel ontbreken.\n\nOpen de instellingen om de URL en streamsleutel in het tabblad 'Stream' in te voeren." +Basic.Settings.Stream.MissingUrl="De stream-URL ontbreekt.\n\nOpen de instellingen om de URL in te voeren in het tabblad 'Stream'." +Basic.Settings.Stream.MissingStreamKey="Stream-sleutel ontbreekt.\n\nOpen instellingen om de stream-sleutel in te voeren in het tabblad 'Stream'." +Basic.Settings.Stream.IgnoreRecommended="Negeer de instellingsaanbevelingen van de streamingservice" +Basic.Settings.Stream.IgnoreRecommended.Warn.Title="Overschrijf aanbevolen instellingen" +Basic.Settings.Stream.IgnoreRecommended.Warn.Text="Waarschuwing: het negeren van de beperkingen van de service kan leiden tot verminderde kwaliteit van de stream of kan voorkomen dat je kunt streamen.\n\nDoorgaan?" +Basic.Settings.Stream.Recommended.MaxVideoBitrate="Maximale Video Bitrate: %1 kbps" +Basic.Settings.Stream.Recommended.MaxAudioBitrate="Maximale Audio Bitrate: %1 kbps" +Basic.Settings.Stream.Recommended.MaxResolution="Maximale Resolutie: %1" +Basic.Settings.Stream.Recommended.MaxFPS="Maximale FPS: %1" Basic.Settings.Output="Uitvoer" Basic.Settings.Output.Format="Opnameformaat" Basic.Settings.Output.Encoder="Encoder" Basic.Settings.Output.SelectDirectory="Selecteer Opnamemap" Basic.Settings.Output.SelectFile="Selecteer Opnamebestand" -Basic.Settings.Output.EnforceBitrate="Forceer bandbreedtelimieten van streaming dienst" Basic.Settings.Output.DynamicBitrate="Dynamisch wijzigen van de bitrate om congestie te beheren" Basic.Settings.Output.DynamicBitrate.Beta="Dynamisch wijzigen van de bitrate om congestie te beheren (Beta)" Basic.Settings.Output.DynamicBitrate.TT="In plaats van frames te laten vallen om congestie te verminderen, verandert de bitrate dynamisch à la minute.\n\nMerk op dat dit de vertraging voor kijkers kan verhogen als er significante plotselinge congestie optreedt.\nAls de bitrate daalt, kan het tot een paar minuten duren om het te herstellen.\n\nMomenteel wordt het alleen ondersteund voor RTMP." @@ -662,10 +675,10 @@ Basic.Settings.Output.Simple.RecordingQuality.Stream="Hetzelfde als de stream" Basic.Settings.Output.Simple.RecordingQuality.Small="Hoge Kwaliteit, Gemiddelde Bestandsgrootte" Basic.Settings.Output.Simple.RecordingQuality.HQ="Ononderscheidbare Kwaliteit, Grote Bestandsgrootte" Basic.Settings.Output.Simple.RecordingQuality.Lossless="Lossless Kwaliteit, Enorm Grote Bestandsgrootte" -Basic.Settings.Output.Simple.Warn.VideoBitrate="Waaschuwing: De video bitrate zal worden ingesteld op %1, dit is de bovengrens van de huidige streaming dienst. Als je zeker weet dat je hoger wil gaan dan %1, schakel dan de geavanceerde encoder-opties in en vink de optie \"Forceer bandbreedtelimieten van streaming dienst\" uit." -Basic.Settings.Output.Simple.Warn.AudioBitrate="Waaschuwing: De audio bitrate zal worden ingesteld op %1, dit is de bovengrens van de huidige streaming dienst. Als je zeker weet dat je hoger wil gaan dan %1, schakel dan de geavanceerde encoder-opties in en vink de optie \"Forceer bandbreedtelimieten van streaming dienst\" uit." -Basic.Settings.Output.Simple.Warn.CannotPause="Waarschuwing: Opnames kunnen niet worden onderbroken als de opnamekwaliteit is ingesteld op \"Hetzelfde als stream\"." -Basic.Settings.Output.Simple.Warn.Encoder="Waarschuwing: Opname met een software-encoder op een andere kwaliteit dan de stream vergt extra cpu-gebruik als je zowel aan het streamen en aan het opnemen bent." +Basic.Settings.Output.Simple.Warn.VideoBitrate="Waarschuwing: de video-bitrate van de stream zal worden ingesteld op %1, wat de bovengrens is van de huidige streamingservice." +Basic.Settings.Output.Simple.Warn.AudioBitrate="Waarschuwing: De audio-bitrate van de stream zal worden ingesteld op %1, wat de bovengrens is van de huidige streamingservice." +Basic.Settings.Output.Simple.Warn.CannotPause="Waarschuwing: opnames kunnen niet worden onderbroken als de opnamekwaliteit is ingesteld op 'Hetzelfde als de stream'." +Basic.Settings.Output.Simple.Warn.Encoder="Waarschuwing: het opnemen met een software-encoder op een andere kwaliteit dan de stream zal extra CPU-gebruik vergen als je zowel streamt als opneemt." Basic.Settings.Output.Simple.Warn.Lossless="Waarschuwing: Lossless kwaliteit genereert erg grote bestanden! Lossless kwaliteit kan tot wel 7 GB aan schijfruimte per minuut gebruiken bij hoge resoluties en framerates. Lossless kwaliteit is niet aanbevolen voor lange opnames tenzij er een grote hoeveelheid schijfruimte beschikbaar is." Basic.Settings.Output.Simple.Warn.Lossless.Msg="Weet je zeker dat je lossless kwaliteit wilt gebruiken?" Basic.Settings.Output.Simple.Warn.Lossless.Title="Lossless kwaliteit waarschuwing!" @@ -674,6 +687,11 @@ 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.Simple.TwitchVodTrack="Twitch VOD Track (Gebruikt Track 2)" +Basic.Settings.Output.Warn.EnforceResolutionFPS.Title="Incompatibele Resolutie/Framerate" +Basic.Settings.Output.Warn.EnforceResolutionFPS.Msg="Deze streamingservice ondersteunt de huidige uitvoerresolutie en/of beeldsnelheid niet; ze zullen worden gewijzigd in de dichtstbijzijnde compatibele waarde:\n\n%1\n\nWil je doorgaan?" +Basic.Settings.Output.Warn.EnforceResolutionFPS.Resolution="Resolutie: %1" +Basic.Settings.Output.Warn.EnforceResolutionFPS.FPS="FPS: %1" Basic.Settings.Output.VideoBitrate="Video Bitrate" Basic.Settings.Output.AudioBitrate="Audio Bitrate" Basic.Settings.Output.Reconnect="Automatisch Opnieuw Verbinden" @@ -682,25 +700,26 @@ Basic.Settings.Output.MaxRetries="Maximaal aantal pogingen" Basic.Settings.Output.Advanced="Geavanceerde Encoderinstellingen Inschakelen" Basic.Settings.Output.EncoderPreset="Encoder Preset" Basic.Settings.Output.CustomEncoderSettings="Aangepaste encoderinstellingen" -Basic.Settings.Output.CustomMuxerSettings="Aangepaste Muxer-instellingen" +Basic.Settings.Output.CustomMuxerSettings="Aangepaste muxer-instellingen" Basic.Settings.Output.NoSpaceFileName="Bestandsnaam zonder spatie genereren" Basic.Settings.Output.Adv.Rescale="Uitvoer Schalen" Basic.Settings.Output.Adv.AudioTrack="Geluidsspoor" Basic.Settings.Output.Adv.Streaming="Streamen" -Basic.Settings.Output.Adv.ApplyServiceSettings="Forceer encoderinstellingen van de streaming dienst" Basic.Settings.Output.Adv.Audio.Track1="Spoor 1" Basic.Settings.Output.Adv.Audio.Track2="Spoor 2" Basic.Settings.Output.Adv.Audio.Track3="Spoor 3" Basic.Settings.Output.Adv.Audio.Track4="Spoor 4" Basic.Settings.Output.Adv.Audio.Track5="Spoor 5" Basic.Settings.Output.Adv.Audio.Track6="Spoor 6" +Basic.Settings.Output.Adv.TwitchVodTrack="Twitch VOD Spoor" Basic.Settings.Output.Adv.Recording="Opnemen" +Basic.Settings.Output.Adv.Recording.RecType="Opnametype" Basic.Settings.Output.Adv.Recording.Type="Type" Basic.Settings.Output.Adv.Recording.Type.Standard="Standaard" Basic.Settings.Output.Adv.Recording.Type.FFmpegOutput="Aangepaste Uitvoer (FFmpeg)" -Basic.Settings.Output.Adv.Recording.UseStreamEncoder="(Gebruik stream encoder)" +Basic.Settings.Output.Adv.Recording.UseStreamEncoder="(Gebruik stream-encoder)" Basic.Settings.Output.Adv.Recording.Filename="Bestandsnaamformaat" Basic.Settings.Output.Adv.Recording.OverwriteIfExists="Overschrijven als bestand bestaat" Basic.Settings.Output.Adv.FFmpeg.Type="FFmpeg Uitvoertype" @@ -770,7 +789,7 @@ Basic.Settings.Audio.PeakMeterType="Piek Meter Type" Basic.Settings.Audio.PeakMeterType.SamplePeak="Sample piek" Basic.Settings.Audio.PeakMeterType.TruePeak="True piek (hogere CPU-gebruik)" Basic.Settings.Audio.MultiChannelWarning.Enabled="Waarschuwing: Surround sound audio is ingeschakeld." -Basic.Settings.Audio.MultichannelWarning="Als je streamt, controleer dan of je streaming service zowel surround sound ingest als surround sound afspelen ondersteunt. Facebook 360 Live is een voorbeeld waar surround sound volledig ondersteund is. Alhoewel Facebook Live en Youtube Live beide surround ingest ondersteunen, downmixt Facebook Live het naar stereo, terwijl Youtube Live slechts twee kanalen afspeelt.\n\nOBS audio filters kunnen overweg met surround sound, maar ondersteuning bij VST plugins is niet gegarandeerd." +Basic.Settings.Audio.MultichannelWarning="Als je streamt, controleer dan of de streamingservice zowel surroundsound-ingest als surroundsound afspelen ondersteunt. Facebook 360 Live is een voorbeeld waar surroundsound volledig ondersteund wordt. Alhoewel Facebook Live en Youtube Live beide surround-ingest ondersteunen, downmixt Facebook Live het naar stereo, terwijl Youtube Live slechts twee kanalen afspeelt.\n\nOBS-audiofilters kunnen overweg met surroundsound, hoewel VST-plugin-support niet gegarandeerd wordt." Basic.Settings.Audio.MultichannelWarning.Title="Surround sound audio inschakelen?" Basic.Settings.Audio.MultichannelWarning.Confirm="Weet je zeker dat je surround sound audio wil inschakelen?" Basic.Settings.Audio.Devices="Globale Audio-apparaten" @@ -794,7 +813,7 @@ Basic.Settings.Advanced.General.ProcessPriority.AboveNormal="Boven Normaal" Basic.Settings.Advanced.General.ProcessPriority.Normal="Normaal" Basic.Settings.Advanced.General.ProcessPriority.BelowNormal="Onder Normaal" Basic.Settings.Advanced.General.ProcessPriority.Idle="Laagst" -Basic.Settings.Advanced.FormatWarning="Waarschuwing: Andere kleurformaten dan NV12 zijn hoofdzakelijk bedoeld voor opnemen en worden niet aanbevolen om mee te streamen. Streamen kan verhoogd CPU-gebruik opleveren vanwege kleurformaatconversie." +Basic.Settings.Advanced.FormatWarning="Waarschuwing: andere kleurformaten dan NV12 zijn hoofdzakelijk bedoeld voor opnemen en worden niet aanbevolen bij streamen. Streamen kan verhoogd CPU-gebruik veroorzaken als gevolg van kleurformaat-conversie." Basic.Settings.Advanced.Audio.BufferingTime="Audio Buffertijd" Basic.Settings.Advanced.Video.ColorFormat="Kleurindeling" Basic.Settings.Advanced.Video.ColorSpace="Kleurruimte" @@ -824,13 +843,18 @@ Basic.AdvAudio="Geavanceerde Audioinstellingen" Basic.AdvAudio.ActiveOnly="Alleen actieve bronnen" Basic.AdvAudio.Name="Naam" Basic.AdvAudio.Volume="Volume" +Basic.AdvAudio.VolumeSource="Volume voor '%1'" Basic.AdvAudio.Mono="Mono" +Basic.AdvAudio.MonoSource="Mono Downmix voor '%1'" Basic.AdvAudio.Balance="Balans" +Basic.AdvAudio.BalanceSource="Balans voor '%1'" Basic.AdvAudio.SyncOffset="Sync Offset" +Basic.AdvAudio.SyncOffsetSource="Sync Offset voor '%1'" Basic.AdvAudio.Monitoring="Audio monitoring" Basic.AdvAudio.Monitoring.None="Niet monitoren" Basic.AdvAudio.Monitoring.MonitorOnly="Alleen monitoren (uitvoer gedempt)" Basic.AdvAudio.Monitoring.Both="Monitoren en uitvoeren" +Basic.AdvAudio.MonitoringSource="Audio monitoring voor '%1'" Basic.AdvAudio.AudioTracks="Sporen" Basic.Settings.Hotkeys="Sneltoetsen" @@ -890,8 +914,8 @@ SceneItemShow="Toon '%1'" SceneItemHide="Verberg '%1'" OutputWarnings.NoTracksSelected="Selecteer a.u.b. ten minste een track" -OutputWarnings.MP4Recording="Waarschuwing: Opnames opgeslagen als MP4/MOV zijn niet te herstellen als de opname niet correct afgerond kan worden (bijvoorbeeld door BSOD's, stroomuitval). Als je wil opnemen met meerdere audiotracks gebruik dan bij voorkeur MKV en remux de opname naar MP4/MOV (Bestand → Remux opnames)" -OutputWarnings.CannotPause="Waarschuwing: Opnames kunnen niet worden gepauzeerd als de opname encoder is ingesteld op \"(Gebruik stream encoder)\"" +OutputWarnings.MP4Recording="Waarschuwing: opnames opgeslagen als MP4/MOV zijn onherstelbaar als het bestand niet correct afgesloten kan worden (bijvoorbeeld door BSOD's, stroomuitval enz.). Als je meersporen-audiotracks wilt opnemen, overweeg dan het gebruik van MKV en remux de opname naar MP4/MOV nadat hij afgerond is (Bestand → Remux opnames)" +OutputWarnings.CannotPause="Waarschuwing: opnames kunnen niet worden gepauzeerd als de opname-encoder is ingesteld op '(Gebruik de stream-encoder)'" FinalScene.Title="Verwijder scène" FinalScene.Text="Er moet tenminste één scène zijn." @@ -907,7 +931,7 @@ CustomColor="Aangepaste kleur" BrowserSource.EnableHardwareAcceleration="Browser bron hardwareversnelling inschakelen" About="Over" -About.Info="OBS Studio is een gratis en open source video recording en live streaming software." +About.Info="OBS-studio is gratis en opensource video-opname- en livestreamsoftware." About.Donate="Maak een bijdrage" About.GetInvolved="Raak betrokken" About.Authors="Auteurs" diff --git a/UI/data/locale/nn-NO.ini b/UI/data/locale/nn-NO.ini index 619c1bb..7065b12 100644 --- a/UI/data/locale/nn-NO.ini +++ b/UI/data/locale/nn-NO.ini @@ -167,6 +167,7 @@ AddProfile.Title="Legg til profil" + Basic.Main.Scenes="Scener" Basic.Main.Sources="Kjelder" Basic.Main.Controls="Kontrollere" diff --git a/UI/data/locale/pa-IN.ini b/UI/data/locale/pa-IN.ini index 89913ab..f0ce659 100644 --- a/UI/data/locale/pa-IN.ini +++ b/UI/data/locale/pa-IN.ini @@ -201,5 +201,6 @@ Updater.UpdateNow="ਹੁਣ ਅਪਡੇਟ ਕਰੋ" + diff --git a/UI/data/locale/pl-PL.ini b/UI/data/locale/pl-PL.ini index 6d2a769..341c3af 100644 --- a/UI/data/locale/pl-PL.ini +++ b/UI/data/locale/pl-PL.ini @@ -161,6 +161,7 @@ Basic.AutoConfig.StreamPage.DisconnectAccount="Odłącz konto" Basic.AutoConfig.StreamPage.DisconnectAccount.Confirm.Title="Odłączyć konto?" Basic.AutoConfig.StreamPage.DisconnectAccount.Confirm.Text="Ta zmiana zostanie zastosowana natychmiast. Czy na pewno chcesz odłączyć konto?" Basic.AutoConfig.StreamPage.GetStreamKey="Pobierz klucz" +Basic.AutoConfig.StreamPage.MoreInfo="Więcej informacji" Basic.AutoConfig.StreamPage.UseStreamKey="Użyj klucza strumienia" Basic.AutoConfig.StreamPage.Service="Serwis" Basic.AutoConfig.StreamPage.Service.ShowAll="Pokaż wszystkie..." @@ -365,8 +366,8 @@ Deinterlacing.Yadif2x="Yadif 2x" Deinterlacing.TopFieldFirst="Najpierw pole górne" Deinterlacing.BottomFieldFirst="Najpierw pole dolne" -VolControl.SliderUnmuted="Suwak głośności dla '%1': %2" -VolControl.SliderMuted="Suwak głośności dla '%1': %2 (obecnie wyciszony)" +VolControl.SliderUnmuted="Suwak głośności dla '%1':" +VolControl.SliderMuted="Suwak głośności dla '%1': (obecnie wyciszony)" VolControl.Mute="Wycisz '%1'" VolControl.Properties="Właściwości dla '%1'" @@ -382,6 +383,7 @@ Basic.Main.RenameSceneCollection.Title="Zmień nazwę zbioru scen" AddProfile.Title="Dodaj profil" AddProfile.Text="Podaj nazwę profilu" +AddProfile.WizardCheckbox="Pokaż kreatora automatycznej konfiguracji" RenameProfile.Title="Zmień nazwę profilu" @@ -396,6 +398,11 @@ Basic.SourceSelect.CreateNew="Stwórz nową" Basic.SourceSelect.AddExisting="Dodaj istniejącą" Basic.SourceSelect.AddVisible="Źródło widoczne" +Basic.Main.Sources.Visibility="Widoczność" +Basic.Main.Sources.VisibilityDescription="Określa widoczność '%1' na wynikowym ekranie" +Basic.Main.Sources.Lock="Blokada" +Basic.Main.Sources.LockDescription="Blokuje pozycję i wielkość '%1' na wynikowym ekranie" + Basic.PropertiesWindow="Właściwości dla '%1'" Basic.PropertiesWindow.AutoSelectFormat="%1 (wybór automatyczny: %2)" Basic.PropertiesWindow.SelectColor="Wybierz kolor" @@ -472,7 +479,7 @@ Basic.Main.StartRecording="Rozpocznij nagrywanie" Basic.Main.StartReplayBuffer="Rozpocznij nagrywanie powtórek" Basic.Main.SaveReplay="Zapisz powtórkę" Basic.Main.StartStreaming="Rozpocznij stream" -Basic.Main.StartVirtualCam="Rozpocznij Kamerę Wirtualną" +Basic.Main.StartVirtualCam="Uruchom Kamerę Wirtualną" Basic.Main.StopRecording="Zatrzymaj nagrywanie" Basic.Main.PauseRecording="Pauzuj nagrywanie" Basic.Main.UnpauseRecording="Wznów nagrywanie" @@ -635,13 +642,19 @@ Basic.Settings.Stream.StreamSettingsWarning="Otwórz Ustawienia" Basic.Settings.Stream.MissingUrlAndApiKey="Brakuje adresu URL i klucza strumienia.\n\nOtwórz ustawienia, aby w zakładce 'Stream' wprowadzić adres URL i klucz strumienia." Basic.Settings.Stream.MissingUrl="Brakuje adresu URL.\n\nOtwórz ustawienia, aby w zakładce 'Stream' wprowadzić adres URL." Basic.Settings.Stream.MissingStreamKey="Brakuje klucza strumienia.\n\nOtwórz ustawienia, aby w zakładce 'Stream' wprowadzić klucz strumienia." +Basic.Settings.Stream.IgnoreRecommended="Ignoruj zalecenia dotyczące ustawień usługi strumieniowej" +Basic.Settings.Stream.IgnoreRecommended.Warn.Title="Nadpisz rekomendowane ustawienia" +Basic.Settings.Stream.IgnoreRecommended.Warn.Text="Ostrzeżenie: Ignorowanie ograniczeń usługi może spowodować pogorszenie jakości strumieniowania lub uniemożliwić przesyłanie strumieniowe.\n\nKontynuować?" +Basic.Settings.Stream.Recommended.MaxVideoBitrate="Maksymalny bitrate: %1 kbps" +Basic.Settings.Stream.Recommended.MaxAudioBitrate="Minimalny bitrate: %1 kbps" +Basic.Settings.Stream.Recommended.MaxResolution="Maksymalna rozdzielczość: %1" +Basic.Settings.Stream.Recommended.MaxFPS="Maksymalna liczba FPS: %1" Basic.Settings.Output="Wyjście" Basic.Settings.Output.Format="Format nagrywania" Basic.Settings.Output.Encoder="Enkoder" Basic.Settings.Output.SelectDirectory="Wybierz katalog nagrywania" Basic.Settings.Output.SelectFile="Wybierz plik nagrania" -Basic.Settings.Output.EnforceBitrate="Wymuś limity przepływności wybranego serwisu" Basic.Settings.Output.DynamicBitrate="Dynamicznie zmień bitrate by zapobiec zapychaniu łącza" Basic.Settings.Output.DynamicBitrate.Beta="Dynamicznie zmień bitrate by zapobiec zapychaniu łącza (beta)" Basic.Settings.Output.DynamicBitrate.TT="Zamiast odrzucać klatki przy zapchanym łączu dynamicznie zmienia bitrate enkodowania.\n\nW przypadku dużego i nagłego przytkania łącza zwiększa to opóźnienie streamu dla oglądających.\nPo zmniejszeniu bitrate, jego powrót do normalnych wartości może potrwać kilka minut.\n\nMechanizm obsługiwany jest obecnie jedynie przy protokole RTMP." @@ -662,8 +675,8 @@ Basic.Settings.Output.Simple.RecordingQuality.Stream="Taka sama jak stream" Basic.Settings.Output.Simple.RecordingQuality.Small="Wysoka jakość, średni rozmiar pliku" Basic.Settings.Output.Simple.RecordingQuality.HQ="Jakość nie do odróżnienia, duża wielkość pliku" Basic.Settings.Output.Simple.RecordingQuality.Lossless="Jakość bezstratna, ogromna wielkość pliku" -Basic.Settings.Output.Simple.Warn.VideoBitrate="Ostrzeżenie: Przepływność (bitrate) obrazu ustawiona jest na wartość %1. Jest to górna granica wartości dozwolonych dla wybranej usługi streamingowej. Aby ustawić wartość przepływności większą niż %1 przejdź do zaawansowanych ustawień dekoder i odznacz opcję \"Wymuś limity przepływności wybranego serwisu\"." -Basic.Settings.Output.Simple.Warn.AudioBitrate="Ostrzeżenie: Przepływność (bitrate) dźwięku ustawiona jest na wartość %1. Jest to górna granica wartości dozwolonych dla wybranej usługi streamingowej. Aby ustawić wartość przepływności większą niż %1, przejdź do zaawansowanych ustawień dekoder i odznacz opcję \"Wymuś limity przepływności wybranego serwisu\"." +Basic.Settings.Output.Simple.Warn.VideoBitrate="Ostrzeżenie: Bitrate obrazu zostanie ustawiony na %1, co jest górnym limitem dla bieżącej usługi strumieniowej." +Basic.Settings.Output.Simple.Warn.AudioBitrate="Ostrzeżenie: Bitrate dźwięku zostanie ustawiony na %1, co jest górnym limitem dla bieżącej usługi strumieniowej." Basic.Settings.Output.Simple.Warn.CannotPause="Ostrzeżenie: Nagrywanie nie może być spauzowane, gdy jakość nagrywania ustawiona jest na \"Taka sama jak stream\"." Basic.Settings.Output.Simple.Warn.Encoder="Ostrzeżenie: Nagrywanie przy użyciu enkodera programowego z jakością inną niż stream wymagać będzie dodatkowej mocy procesora w przypadku jednoczesnego streamowania i nagrywania." Basic.Settings.Output.Simple.Warn.Lossless="Ostrzeżenie: Jakość bezstratna generuje bardzo duże pliki! Przy dużych rozdzielczościach i szybkości klatek rozmiar pliku może sięgać 7GB na minutę nagrania. Jakość ta nie jest zalecana w przypadku długich nagrań, chyba że masz bardzo dużo wolnego miejsca na dysku." @@ -674,6 +687,11 @@ 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.Simple.TwitchVodTrack="Ścieżka VOD Twitch (korzysta ze ścieżki 2)" +Basic.Settings.Output.Warn.EnforceResolutionFPS.Title="Niekompatybilna rozdzielczość/liczba FPS" +Basic.Settings.Output.Warn.EnforceResolutionFPS.Msg="Ta usługa strumieniowania nie obsługuje Twojej aktualnej rozdzielczości wyjściowej i/lub liczby FPS. Zostaną one zmienione na najbliższą kompatybilną wartość:\n\n%1\n\nCzy chcesz kontynuować?" +Basic.Settings.Output.Warn.EnforceResolutionFPS.Resolution="Rozdzielczość: %1" +Basic.Settings.Output.Warn.EnforceResolutionFPS.FPS="FPS: %1" Basic.Settings.Output.VideoBitrate="Bitrate obrazu" Basic.Settings.Output.AudioBitrate="Bitrate dźwięku" Basic.Settings.Output.Reconnect="Ponowne łączenie" @@ -688,15 +706,16 @@ Basic.Settings.Output.NoSpaceFileName="Generuj nazwę pliku bez spacji" Basic.Settings.Output.Adv.Rescale="Przeskaluj wyjściowy obraz" Basic.Settings.Output.Adv.AudioTrack="Ścieżki dźwiękowe" Basic.Settings.Output.Adv.Streaming="Streaming" -Basic.Settings.Output.Adv.ApplyServiceSettings="Wymuś ustawienia enkodera dla danego serwisu" Basic.Settings.Output.Adv.Audio.Track1="Ścieżka 1" Basic.Settings.Output.Adv.Audio.Track2="Ścieżka 2" Basic.Settings.Output.Adv.Audio.Track3="Ścieżka 3" Basic.Settings.Output.Adv.Audio.Track4="Ścieżka 4" Basic.Settings.Output.Adv.Audio.Track5="Ścieżka 5" Basic.Settings.Output.Adv.Audio.Track6="Ścieżka 6" +Basic.Settings.Output.Adv.TwitchVodTrack="Ścieżka Twitch VOD" Basic.Settings.Output.Adv.Recording="Nagrywanie" +Basic.Settings.Output.Adv.Recording.RecType="Typ nagrania" Basic.Settings.Output.Adv.Recording.Type="Typ" Basic.Settings.Output.Adv.Recording.Type.Standard="Standardowe" Basic.Settings.Output.Adv.Recording.Type.FFmpegOutput="Niestandardowe ustawienia (FFmpeg)" @@ -824,13 +843,18 @@ Basic.AdvAudio="Zaawansowane ustawienia dźwięku" Basic.AdvAudio.ActiveOnly="Tylko aktywne źródła" Basic.AdvAudio.Name="Nazwa" Basic.AdvAudio.Volume="Głośność" +Basic.AdvAudio.VolumeSource="Głośność dla '%1'" Basic.AdvAudio.Mono="Mono" +Basic.AdvAudio.MonoSource="Miks do mono dla '%1'" Basic.AdvAudio.Balance="Balans" +Basic.AdvAudio.BalanceSource="Balans dla '%1'" Basic.AdvAudio.SyncOffset="Przesunięcie dźwięku" +Basic.AdvAudio.SyncOffsetSource="Przesunięcie synchronizacji dla '%1'" Basic.AdvAudio.Monitoring="Monitorowanie urządzenia audio" Basic.AdvAudio.Monitoring.None="Wyłączone" Basic.AdvAudio.Monitoring.MonitorOnly="Tylko monitorowanie (wyjście wyłączone)" Basic.AdvAudio.Monitoring.Both="Monitorowanie i przekazywanie na wyjście" +Basic.AdvAudio.MonitoringSource="Monitorowanie dźwięku dla '%1'" Basic.AdvAudio.AudioTracks="Ścieżki" Basic.Settings.Hotkeys="Skróty klawiszowe" diff --git a/UI/data/locale/pt-BR.ini b/UI/data/locale/pt-BR.ini index c34ffb3..3c1c181 100644 --- a/UI/data/locale/pt-BR.ini +++ b/UI/data/locale/pt-BR.ini @@ -1,7 +1,7 @@ -Language="Português" +Language="Português brasileiro" -OK="Ok" +OK="OK" Apply="Aplicar" Cancel="Cancelar" Close="Fechar" @@ -21,48 +21,48 @@ MoveDown="Mover para baixo" Settings="Configurações" Display="Monitor" Name="Nome" -Exit="Sair" -Mixer="Mixer de Áudio" -Browse="Localizar" +Exit="Encerrar OBS" +Mixer="Mixer de áudio" +Browse="Explorar" Mono="Mono" Stereo="Estéreo" DroppedFrames="Quadros perdidos %1 (%2%)" -StudioProgramProjector="Projetor em tela inteira (programa)" -PreviewProjector="Projetor em tela inteira (pré-visualização)" -SceneProjector="Projetor em tela inteira (cena)" -SourceProjector="Projetor em tela inteira (fonte)" +StudioProgramProjector="Projetor em tela cheia (programa)" +PreviewProjector="Projetor em tela cheia (prévia)" +SceneProjector="Projetor em tela cheia (cena)" +SourceProjector="Projetor em tela cheia (fonte)" StudioProgramWindow="Projetor em janela (programa)" -PreviewWindow="Projetor em janela (pré-visualização)" +PreviewWindow="Projetor em janela (prévia)" SceneWindow="Projetor em janela (cena)" -SourceWindow="Projetor em janela (Fonte)" -MultiviewProjector="Visualização múltipla (tela inteira)" +SourceWindow="Projetor em janela (fonte)" +MultiviewProjector="Visualização múltipla (tela cheia)" MultiviewWindowed="Visualização múltipla (janela)" ResizeProjectorWindowToContent="Ajustar janela ao conteúdo" Clear="Limpar" Revert="Desfazer" -Show="Exibir" +Show="Mostrar" Hide="Ocultar" UnhideAll="Mostrar tudo" Untitled="Sem nome" New="Novo" Duplicate="Duplicar" Enable="Habilitar" -DisableOSXVSync="Desabilitar V-Sync em macOS" -ResetOSXVSyncOnExit="Redefinir V-Sync em macOS na saída" -HighResourceUsage="Codificação sobrecarregada! Considere abaixar as configurações de vídeo ou usar um padrão de codificação mais rápido." +DisableOSXVSync="Desativar sincronização vertical do macOS" +ResetOSXVSyncOnExit="Redefinir sincronização vertical do macOS ao encerrar o OBS" +HighResourceUsage="Codificação sobrecarregada! Considere reduzir as configurações de vídeo ou usar um padrão de codificação mais rápido." Transition="Transição" QuickTransitions="Transições rápidas" -FadeToBlack="Desvanecer para Preto" +FadeToBlack="Desvanecer para preto" Left="Esquerda" Right="Direita" -Top="Topo" +Top="Cima" Bottom="Baixo" Reset="Redefinir" Hours="Horas" Minutes="Minutos" Seconds="Segundos" Deprecated="Obsoleto" -ReplayBuffer="Buffer de Repetição" +ReplayBuffer="Buffer de repetição" Import="Importar" Export="Exportar" Copy="Copiar" @@ -72,9 +72,9 @@ PasteDuplicate="Colar (duplicar)" RemuxRecordings="Converter gravações" Next="Avançar" Back="Voltar" -Defaults="Padrões" -HideMixer="Esconder no Mixer" -TransitionOverride="Substituição de Transição" +Defaults="Redefinir" +HideMixer="Esconder no mixer" +TransitionOverride="Sobrepor transição" None="Nenhuma" StudioMode.Preview="Prévia" StudioMode.Program="Programa" @@ -84,14 +84,14 @@ Group="Grupo" DoNotShowAgain="Não mostrar novamente" Default="(Padrão)" Calculating="Calculando..." -Fullscreen="Tela Cheia" -Windowed="Em janela" -Percent="Por cento" +Fullscreen="Tela cheia" +Windowed="Janela" +Percent="por cento" RefreshBrowser="Atualizar" AspectRatio="Proporção da tela %1:%2" -LockVolume="Travar Volume" -LogViewer="Visualizador de registro" -ShowOnStartup="Exibir ao iniciar" +LockVolume="Travar volume" +LogViewer="Registros" +ShowOnStartup="Mostrar na inicialização" OpenFile="Abrir arquivo" AddValue="Adicionar %1" @@ -99,159 +99,160 @@ AlreadyRunning.Title="OBS já está em execução" AlreadyRunning.Text="OBS já está em execução! A menos que você tenha a intenção de fazer isso, por favor, feche todas as instâncias existentes do OBS antes de tentar executar uma nova. Se você tiver definido para minimizar o OBS na bandeja do sistema, verifique se ainda está lá em execução." AlreadyRunning.LaunchAnyway="Executar mesmo assim" -ChromeOS.Title="Plataforma Não Suportada" -ChromeOS.Text="O OBS parece estar sendo executado dentro de um contêiner ChromeOS. Esta plataforma não é suportada" +ChromeOS.Title="Plataforma não suportada" +ChromeOS.Text="Aparentemente, o OBS está sendo executado em um ChromeOS. Esta plataforma não é suportada" -DockCloseWarning.Title="Fechar janela ancorável" -DockCloseWarning.Text="Você acabou de fechar uma janela ancorável. Se você gostaria de abri-la novamente, use o menu Mostrar → Docas." +DockCloseWarning.Title="Fechar janela de aba personalizada" +DockCloseWarning.Text="Você acabou de fechar a janela de uma aba personalizada. Se você gostaria de abri-la novamente, use o menu Visualizar → Abas." -ExtraBrowsers="Docas para Navegador Personalizado" -ExtraBrowsers.Info="Adicione docas dando-lhes um nome e URL, então clique em Aplicar ou Fechar para abrir as docas. Você pode adicionar ou remover as docas a qualquer momento." -ExtraBrowsers.DockName="Nome da Doca" +ExtraBrowsers="Abas personalizáveis com URL" +ExtraBrowsers.Info="Adicione abas fornecendo um nome e URL, então clique em Aplicar ou Fechar para abrir as abas. Você pode adicionar ou remover as abas a qualquer momento." +ExtraBrowsers.DockName="Nome da aba" Auth.Authing.Title="Autenticando..." -Auth.Authing.Text="Autenticando com a(o) %1, aguarde..." -Auth.AuthFailure.Title="Falha na Autenticação" -Auth.AuthFailure.Text="Falha na Autenticação com a(o)%1:\n\n%2: %3" -Auth.InvalidScope.Title="Autenticação Necessária" -Auth.InvalidScope.Text="Os requisitos de autenticação para %1 foram alterados. Alguns recursos podem não estar disponíveis." +Auth.Authing.Text="Autenticando com %1, aguarde..." +Auth.AuthFailure.Title="Falha na autenticação" +Auth.AuthFailure.Text="Falha ao autenticar com %1:\n\n%2: %3" +Auth.InvalidScope.Title="Autenticação necessária" +Auth.InvalidScope.Text="Os requisitos de autenticação do(a) %1 foram alterados. Alguns recursos podem não estar disponíveis." Auth.LoadingChannel.Title="Carregando informações do canal..." -Auth.LoadingChannel.Text="Carregando informações do canal para %1. Por favor, aguarde..." -Auth.ChannelFailure.Title="Erro ao carregar canal" -Auth.ChannelFailure.Text="Erro ao carregar informaões do canal da(o) %1\n\n%2: %3" +Auth.LoadingChannel.Text="Carregando informações do canal do(a) %1, aguarde..." +Auth.ChannelFailure.Title="Não foi possível carregar o canal" +Auth.ChannelFailure.Text="Não foi possível carregar informações do canal do(a) %1\n\n%2: %3" Auth.Chat="Chat" -Auth.StreamInfo="Informação da transmissão" +Auth.StreamInfo="Informações da transmissão" TwitchAuth.Stats="Estatísticas da Twitch" -TwitchAuth.Feed="Feed de Atividade do Twitch" +TwitchAuth.Feed="Feed de atividade da Twitch" TwitchAuth.TwoFactorFail.Title="Não foi possível consultar a chave de transmissão" -TwitchAuth.TwoFactorFail.Text="O OBS não foi capaz de se conectar à sua conta do Twitch. Por favor, certifique-se de que a autenticação de dois fatores está configurada em suas Configurações de segurança do Twitch pois isso é necessário para transmitir." +TwitchAuth.TwoFactorFail.Text="Não foi possível conectar à sua conta do Twitch. Por favor, certifique-se de que a autenticação de dois fatores está configurada em suas Configurações de segurança da Twitch pois isso é necessário para transmitir." RestreamAuth.Channels="Canais do Restream" -Copy.Filters="Copiar Filtros" -Paste.Filters="Colar Filtros" +Copy.Filters="Copiar filtros" +Paste.Filters="Colar filtros" -BrowserPanelInit.Title="Inicializando o Navegador..." +BrowserPanelInit.Title="Inicializando o navegador..." BrowserPanelInit.Text="Inicializando o navegador, aguarde..." BandwidthTest.Region="Região" BandwidthTest.Region.US="Estados Unidos" BandwidthTest.Region.EU="Europa" BandwidthTest.Region.Asia="Ásia" -BandwidthTest.Region.Other="Outro" +BandwidthTest.Region.Other="Outra" Basic.AutoConfig="Assistente de configuração" -Basic.AutoConfig.ApplySettings="Aplicar Configurações" -Basic.AutoConfig.StartPage="Informações de Uso" +Basic.AutoConfig.ApplySettings="Aplicar configurações" +Basic.AutoConfig.StartPage="Informações de uso" Basic.AutoConfig.StartPage.SubTitle="Marque para que você deseja usar o programa" Basic.AutoConfig.StartPage.PrioritizeStreaming="Otimizar para transmissão, gravação é opcional" Basic.AutoConfig.StartPage.PrioritizeRecording="Otimizar somente para gravação, eu não farei transmissão" -Basic.AutoConfig.StartPage.PrioritizeVirtualCam="Apenas usarei a câmera virtual" -Basic.AutoConfig.VideoPage="Configurações de Vídeo" -Basic.AutoConfig.VideoPage.SubTitle="Especifique as configurações do vídeo que você gostaria de usar" -Basic.AutoConfig.VideoPage.BaseResolution.UseCurrent="Usar Atual (%1x%2)" +Basic.AutoConfig.StartPage.PrioritizeVirtualCam="Usarei apenas a câmera virtual" +Basic.AutoConfig.VideoPage="Configurações de vídeo" +Basic.AutoConfig.VideoPage.SubTitle="Especifique as configurações de vídeo que você gostaria de usar" +Basic.AutoConfig.VideoPage.BaseResolution.UseCurrent="Usar atual (%1x%2)" Basic.AutoConfig.VideoPage.BaseResolution.Display="Monitor %1 (%2x%3)" -Basic.AutoConfig.VideoPage.FPS.UseCurrent="Usar Atual (%1)" +Basic.AutoConfig.VideoPage.FPS.UseCurrent="Usar atual (%1)" Basic.AutoConfig.VideoPage.FPS.PreferHighFPS="60 ou 30, mas prefiro 60 quando possível" Basic.AutoConfig.VideoPage.FPS.PreferHighRes="60 ou 30, mas prefiro alta resolução" -Basic.AutoConfig.VideoPage.CanvasExplanation="Nota: A resolução da tela (base) não é necessariamente a mesma resolução que você transmitirá ou gravará. Sua resolução final da transmissão/gravação pode ser redimencionada da resolução da tela para reduzir o uso de recursos ou bitrate necessário." +Basic.AutoConfig.VideoPage.CanvasExplanation="Nota: A resolução da tela (base) não é necessariamente a mesma resolução que você transmitirá ou gravará. Sua resolução final da transmissão/gravação pode ser redimensionada da resolução da tela para reduzir o uso de recursos ou taxa de bits necessários." Basic.AutoConfig.StreamPage="Informações da transmissão" -Basic.AutoConfig.StreamPage.SubTitle="Por favor, digite suas informações para a transmissão" -Basic.AutoConfig.StreamPage.ConnectAccount="Conectar Conta (recomendado)" -Basic.AutoConfig.StreamPage.DisconnectAccount="Desconectar Conta" +Basic.AutoConfig.StreamPage.SubTitle="Por favor, digite suas informações de transmissão" +Basic.AutoConfig.StreamPage.ConnectAccount="Conectar conta (recomendado)" +Basic.AutoConfig.StreamPage.DisconnectAccount="Desconectar conta" Basic.AutoConfig.StreamPage.DisconnectAccount.Confirm.Title="Desconectar conta?" -Basic.AutoConfig.StreamPage.DisconnectAccount.Confirm.Text="Esta mudança será aplicada imediatamente. Tem certeza de que deseja desconectar sua conta?" -Basic.AutoConfig.StreamPage.GetStreamKey="Obter chave da transmissão" -Basic.AutoConfig.StreamPage.UseStreamKey="Usar chave da transmissão" +Basic.AutoConfig.StreamPage.DisconnectAccount.Confirm.Text="Esta mudança será aplicada imediatamente. Deseja mesmo desconectar sua conta?" +Basic.AutoConfig.StreamPage.GetStreamKey="Obter chave de transmissão" +Basic.AutoConfig.StreamPage.MoreInfo="Mais informações" +Basic.AutoConfig.StreamPage.UseStreamKey="Usar chave de transmissão" Basic.AutoConfig.StreamPage.Service="Serviço" Basic.AutoConfig.StreamPage.Service.ShowAll="Mostrar todos..." Basic.AutoConfig.StreamPage.Service.Custom="Personalizado..." Basic.AutoConfig.StreamPage.Server="Servidor" -Basic.AutoConfig.StreamPage.StreamKey="Chave da transmissão" +Basic.AutoConfig.StreamPage.StreamKey="Chave de transmissão" Basic.AutoConfig.StreamPage.StreamKey.LinkToSite="(Link)" Basic.AutoConfig.StreamPage.PerformBandwidthTest="Estimar taxa de bits com teste de largura de banda (pode levar uns minutos)" Basic.AutoConfig.StreamPage.PreferHardwareEncoding="Preferir codificação por hardware" -Basic.AutoConfig.StreamPage.PreferHardwareEncoding.ToolTip="Codificação por Hardware elimina a maioria do uso de CPU, mas pode exigir uma taxa de bits maior para obter o mesmo nível de qualidade." +Basic.AutoConfig.StreamPage.PreferHardwareEncoding.ToolTip="Codificação por hardware elimina boa parte do uso de CPU, mas pode exigir uma taxa de bits maior para obter o mesmo nível de qualidade." Basic.AutoConfig.StreamPage.StreamWarning.Title="Aviso de transmissão" Basic.AutoConfig.StreamPage.StreamWarning.Text="O teste de largura de banda está prestes a transmitir imagens aleatórias e sem áudio para o seu canal. Se for possível, é recomendável desativar temporariamente a gravação da transmissão e definir a transmissão como privada até que o teste seja concluído. Continuar?" -Basic.AutoConfig.TestPage="Resultados Finais" +Basic.AutoConfig.TestPage="Resultados finais" Basic.AutoConfig.TestPage.SubTitle.Testing="O programa está executando um conjunto de testes para estimar as configurações ideais" Basic.AutoConfig.TestPage.SubTitle.Complete="Teste completo" -Basic.AutoConfig.TestPage.TestingBandwidth="Executando teste de largura de banda, isso pode levar alguns minutos..." +Basic.AutoConfig.TestPage.TestingBandwidth="Executando teste de largura de banda, isto pode levar alguns minutos..." Basic.AutoConfig.TestPage.TestingBandwidth.Connecting="Conectando a: %1..." -Basic.AutoConfig.TestPage.TestingBandwidth.ConnectFailed="Falha ao se conectar a qualquer servidor, verifique sua conexão com a Internet e tente novamente." -Basic.AutoConfig.TestPage.TestingBandwidth.Server="Teste de largura de banda para: %1" -Basic.AutoConfig.TestPage.TestingStreamEncoder="Testando codificador de transmissão, isto pode demorar um minuto..." -Basic.AutoConfig.TestPage.TestingRecordingEncoder="Testando codificador de gravação, isto pode demorar um minuto..." +Basic.AutoConfig.TestPage.TestingBandwidth.ConnectFailed="Não foi possível conectar nenhum servidor, verifique sua conexão com a internet e tente novamente." +Basic.AutoConfig.TestPage.TestingBandwidth.Server="Testando largura de banda para: %1" +Basic.AutoConfig.TestPage.TestingStreamEncoder="Testando codificador de transmissão, isto pode levar um minuto..." +Basic.AutoConfig.TestPage.TestingRecordingEncoder="Testando codificador de gravação, isto pode levar um minuto..." Basic.AutoConfig.TestPage.TestingRes="Testando resoluções, isto pode levar alguns minutos..." Basic.AutoConfig.TestPage.TestingRes.Fail="Falha ao iniciar o codificador" -Basic.AutoConfig.TestPage.TestingRes.Resolution="Testando %1x%2 %3 QPS..." +Basic.AutoConfig.TestPage.TestingRes.Resolution="Testando %1x%2 a %3 quadros por segundo..." Basic.AutoConfig.TestPage.Result.StreamingEncoder="Codificador da transmissão" -Basic.AutoConfig.TestPage.Result.RecordingEncoder="Codificador da Gravação" -Basic.AutoConfig.TestPage.Result.Header="O programa determinou que estas configurações estimadas são as mais ideais para você:" -Basic.AutoConfig.TestPage.Result.Footer="Para usar essas configurações, clique em \"Aplicar Configurações\". Para reconfigurar o assistente e tentar novamente, clique em \"Voltar\". Para definir manualmente, clique em \"Cancelar\" e abra as \"Configurações\"." -Basic.AutoConfig.Info="O assistente de configuração automática irá determinar as melhores configurações baseadas nas especificações do seu computador e na velocidade da internet." -Basic.AutoConfig.RunAnytime="Isto pode ser executado a qualquer momento indo para o menu Ferramentas." +Basic.AutoConfig.TestPage.Result.RecordingEncoder="Codificador da gravação" +Basic.AutoConfig.TestPage.Result.Header="O programa recomenda as seguintes configurações pra você:" +Basic.AutoConfig.TestPage.Result.Footer="Para usar essas configurações, clique em Aplicar configurações. Para reconfigurar o assistente e tentar novamente, clique em Voltar. Para definir manualmente, clique em Cancelar e abra as Configurações." +Basic.AutoConfig.Info="O assistente de configuração irá determinar as melhores configurações baseadas nas especificações do seu computador e na velocidade da internet." +Basic.AutoConfig.RunAnytime="Isto pode ser executado a qualquer momento no menu Ferramentas." Basic.Stats="Estatísticas" Basic.Stats.CPUUsage="Uso de CPU" Basic.Stats.HDDSpaceAvailable="Espaço em disco disponível" -Basic.Stats.MemoryUsage="Uso de Memória" -Basic.Stats.AverageTimeToRender="Tempo médio para renderizar quadro" -Basic.Stats.SkippedFrames="Quadros ignorados devido a demora na codificação" -Basic.Stats.MissedFrames="Quadros perdidos devido a demora na renderização" +Basic.Stats.MemoryUsage="Uso de memória" +Basic.Stats.AverageTimeToRender="Tempo médio para renderizar um quadro" +Basic.Stats.SkippedFrames="Quadros ignorados devido à demora na codificação" +Basic.Stats.MissedFrames="Quadros perdidos devido à demora na renderização" Basic.Stats.Output.Stream="Transmissão" Basic.Stats.Output.Recording="Gravação" Basic.Stats.Status="Status" Basic.Stats.Status.Recording="Gravando" -Basic.Stats.Status.Live="AO VIVO" +Basic.Stats.Status.Live="NO AR" Basic.Stats.Status.Reconnecting="Reconectando" Basic.Stats.Status.Inactive="Inativa" -Basic.Stats.Status.Active="Ativar" -Basic.Stats.DroppedFrames="Quadros Perdidos (Rede)" -Basic.Stats.MegabytesSent="Saída Total de Dados" +Basic.Stats.Status.Active="Ativa" +Basic.Stats.DroppedFrames="Quadros perdidos (rede)" +Basic.Stats.MegabytesSent="Saída total de dados" Basic.Stats.Bitrate="Taxa de bits" -Basic.Stats.DiskFullIn="Disco completo em (aprox.)" -Basic.Stats.ResetStats="Redefinir Status" +Basic.Stats.DiskFullIn="Disco cheio em (aprox.)" +Basic.Stats.ResetStats="Redefinir status" -ResetUIWarning.Title="Tem certeza de que deseja redefinir a interface do usuário?" -ResetUIWarning.Text="Redefinir a interface irá ocultar as docas adicionais. Você precisará mostra-las indo no menu de visualização se quiser que elas se tornem visíveis novamente.\n\nTem certeza de que deseja redefinir a interface do usuário?" +ResetUIWarning.Title="Deseja mesmo redefinir a interface?" +ResetUIWarning.Text="Redefinir a interface irá ocultar as abas extras. Você precisará ir no menu Visualizar se quiser que elas se tornem visíveis novamente.\n\Deseja mesmo redefinir a interface?" Updater.Title="Nova atualização disponível" Updater.Text="Há uma nova atualização disponível:" Updater.UpdateNow="Atualizar agora" Updater.RemindMeLater="Lembre-me depois" -Updater.Skip="Pular Versão" -Updater.Running.Title="Programa atualmente em execução" +Updater.Skip="Ignorar" +Updater.Running.Title="Programa em execução" Updater.Running.Text="Saídas estão atualmente ativas, por favor desligue quaisquer saídas ativas antes de tentar atualizar" Updater.NoUpdatesAvailable.Title="Nenhuma atualização disponível" -Updater.NoUpdatesAvailable.Text="Não há atualizações disponíveis" +Updater.NoUpdatesAvailable.Text="Nenhuma atualização disponível no momento" Updater.FailedToLaunch="Falha ao iniciar o atualizador" Updater.GameCaptureActive.Title="Captura de jogo ativa" Updater.GameCaptureActive.Text="A biblioteca de captura do jogo está em uso no momento. Por favor feche qualquer jogo/programa que esteja sendo capturado (ou reinicie o Windows) e tente novamente." -QuickTransitions.SwapScenes="Trocar Cenas de Prévia/Saída após a Transição" +QuickTransitions.SwapScenes="Alternar entre cenas de prévia e saída após a transição" QuickTransitions.SwapScenesTT="Troca a prévia e a saída após transicionar (se a a cena original de saída ainda exisitr).\nIsto não irá desfazer nenhuma mudança que foi feita na cena original da saída." -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="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" +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 \"Duplicar fontes\".\nMudar este valor irá redefinir a cena atual de saída (se ainda existir)." +QuickTransitions.EditProperties="Duplicar fontes" +QuickTransitions.EditPropertiesTT="Quanto estiver editando a mesma cena, permite editar as propriedades de fontes sem modificar o resultado.\nIsso só pode ser usado se 'Duplicar cena' estiver ativado.\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 atual (se ainda existir uma)\n\nAviso: Devido às fontes serem 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" -Basic.RemoveTransition="Remover Transição Configurável" -Basic.TransitionProperties="Propriedades da Transição" -Basic.SceneTransitions="Transições de Cena" +Basic.AddTransition="Adicionar transição configurável" +Basic.RemoveTransition="Remover transição configurável" +Basic.TransitionProperties="Propriedades da transição" +Basic.SceneTransitions="Transições de cena" Basic.TransitionDuration="Duração" -Basic.TogglePreviewProgramMode="Modo Estúdio" +Basic.TogglePreviewProgramMode="Modo estúdio" TransitionNameDlg.Text="Por favor, insira o nome da transição" -TransitionNameDlg.Title="Nome da Transição" +TransitionNameDlg.Title="Nome da transição" TitleBar.Profile="Perfil" TitleBar.Scenes="Cenas" -NameExists.Title="Nome Existente" -NameExists.Text="O Nome já está em uso." +NameExists.Title="Nome existente" +NameExists.Text="Esse nome já está em uso." NoNameEntered.Title="Por favor, insira um nome válido" NoNameEntered.Text="Você não pode usar nomes vazios." @@ -262,33 +263,33 @@ ConfirmStart.Text="Deseja mesmo iniciar a transmissão?" ConfirmStop.Title="Interromper transmissão?" ConfirmStop.Text="Deseja mesmo interromper a transmissão?" -ConfirmStopRecord.Title="Parar Gravação?" -ConfirmStopRecord.Text="Tem certeza que deseja parar a gravação?" +ConfirmStopRecord.Title="Interromper gravação?" +ConfirmStopRecord.Text="Deseja mesmo interromper a gravação?" ConfirmBWTest.Title="Iniciar teste de largura de banda?" -ConfirmBWTest.Text="Você com o OBS configurado no modo de teste de largura de banda. Este modo permite o teste de rede sem que o seu canal entre em funcionamento. Uma vez terminado o teste, você precisará desativá-lo para que os espectadores possam ver sua transmissão.\n\nVocê quer continuar?" +ConfirmBWTest.Text="Você está com o OBS configurado no modo de teste de largura de banda. Este modo permite o teste de rede sem que o seu canal entre em funcionamento. Uma vez terminado o teste, você precisará desativá-lo para que os espectadores possam ver sua transmissão.\n\nVocê quer continuar?" -ConfirmExit.Title="Sair do OBS?" -ConfirmExit.Text="OBS está ativo no momento. Todos as streams/gravações serão encerradas. Tem certeza que deseja sair?" +ConfirmExit.Title="Encerrar OBS?" +ConfirmExit.Text="OBS está ativo no momento. Todas as transmissões e/ou gravações serão interrompidas. Deseja mesmo encerrar o programa?" -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?" +ConfirmRemove.Title="Confirmar a remoção" +ConfirmRemove.Text="Deseja mesmo remover '$1'?" +ConfirmRemove.TextMultiple="Deseja mesmo remover %1 itens?" Output.StartStreamFailed="Falha ao iniciar a transmissão" Output.StartRecordingFailed="Falha ao iniciar a gravação" Output.StartReplayFailed="Falha ao iniciar o buffer de repetição" -Output.StartFailedGeneric="Impossível criar o arquivo de saída. Verifique o registro para mais detalhes do erro.\n\nAviso: se estiver utilizando os codificadores NVENC ou AMD, certifique-se de que os seus drivers estão atualizados." +Output.StartFailedGeneric="Não foi possível criar o arquivo de saída. Verifique o registro para mais detalhes do erro.\n\nAviso: se estiver utilizando os codificadores NVENC ou AMD, certifique-se de que os seus drivers estão atualizados." Output.ReplayBuffer.PauseWarning.Title="Não é possível salvar replays enquanto pausado" -Output.ReplayBuffer.PauseWarning.Text="Aviso: Replays não podem ser salvos enquanto a gravação estiver pausada." +Output.ReplayBuffer.PauseWarning.Text="Aviso: replays não podem ser salvos enquanto a gravação estiver pausada." Output.ConnectFail.Title="Falha ao conectar" Output.ConnectFail.BadPath="Caminho ou URL inválida. Por favor, verifique suas configurações para confirmar que estão válidas." -Output.ConnectFail.ConnectFailed="Falha ao conectar com o Servidor" +Output.ConnectFail.ConnectFailed="Não foi possível conectar ao servidor" Output.ConnectFail.InvalidStream="Não foi possível acessar o canal especificado ou a chave de transmissão, verifique a sua chave de transmissão. Se estiver correta, pode haver um problema de conexão com o servidor." Output.ConnectFail.Error="Ocorreu um erro inesperado ao tentar conectar-se ao servidor. Verifique o arquivo de registro para mais informações." -Output.ConnectFail.Disconnected="Desconectado do Servidor." +Output.ConnectFail.Disconnected="Desconectado do servidor." Output.StreamEncodeError.Title="Erro de codificação" Output.StreamEncodeError.Msg="Ocorreu um erro de codificação durante a transmissão." @@ -301,12 +302,12 @@ Output.RecordError.Title="Erro de gravação" Output.RecordError.Msg="Ocorreu um erro não especificado durante a gravação." Output.RecordError.EncodeErrorMsg="Ocorreu um erro de codificação durante a gravação." -Output.BadPath.Title="Caminho de Arquivo Inválido" -Output.BadPath.Text="O caminho do arquivo de saída é inválido. Por Favor, certifique-se de que um caminho válido foi informado." +Output.BadPath.Title="Caminho de arquivo inválido" +Output.BadPath.Text="O caminho do arquivo de saída é inválido. Por favor, certifique-se de informar um caminho válido." LogReturnDialog="Carregamento do arquivo de registro efetuado com êxito" -LogReturnDialog.Description="Seu arquivo de log foi enviado. Agora você pode compartilhar a URL para fins de depuração ou suporte." -LogReturnDialog.Description.Crash="Seu relatório de falha foi enviado. Agora você pode compartilhar o URL para fins de depuração." +LogReturnDialog.Description="Seu arquivo de registro foi enviado. Agora você pode compartilhar a URL para fins de depuração ou suporte." +LogReturnDialog.Description.Crash="Seu relatório de falha foi enviado. Agora você pode compartilhar a URL para fins de depuração." LogReturnDialog.CopyURL="Copiar URL" LogReturnDialog.AnalyzeURL="Analisar" LogReturnDialog.ErrorUploadingLog="Erro no carregamento do arquivo de registro" @@ -325,15 +326,15 @@ Remux.SelectRecording="Selecione uma gravação do OBS..." Remux.SelectTarget="Selecione o arquivo de destino..." Remux.FileExistsTitle="O arquivo de destino já existe" Remux.FileExists="Os seguintes arquivos já existem. Você deseja substituí-los?" -Remux.ExitUnfinishedTitle="Conversão em curso" +Remux.ExitUnfinishedTitle="Conversão em andamento" Remux.ExitUnfinished="Conversão não concluída, parar agora pode tornar o arquivo de destino inutilizável.\nTem certeza que deseja parar a conversão?" -Remux.HelpText="Solte arquivos nesta janela para converter ou selecione uma célula \"Gravação do OBS\" para buscar um arquivo." +Remux.HelpText="Arraste arquivos para esta janela para converter ou clique em \"Gravação do OBS\" para localizar um arquivo." -UpdateAvailable="Nova Atualização Disponível" -UpdateAvailable.Text="Versão %1.%2.%3 está agora disponível. clique aqui para baixar" +UpdateAvailable="Nova atualização disponível" +UpdateAvailable.Text="A versão %1.%2.%3 já está disponível. Clique aqui para fazer download" -Basic.DesktopDevice1="Desktop Áudio" -Basic.DesktopDevice2="Desktop Áudio 2" +Basic.DesktopDevice1="Áudio do desktop" +Basic.DesktopDevice2="Áudio do desktop 2" Basic.AuxDevice1="Mic/Aux" Basic.AuxDevice2="Mic/Aux 2" Basic.AuxDevice3="Mic/Aux 3" @@ -342,9 +343,9 @@ Basic.AuxDevice4="Mic/Aux 4" Basic.Scene="Cena" Basic.DisplayCapture="Captura de tela" -Basic.Main.PreviewConextMenu.Enable="Ativar pré-visualização" +Basic.Main.PreviewConextMenu.Enable="Ativar prévia" -Basic.Main.Preview.Disable="Desativar pré-visualização" +Basic.Main.Preview.Disable="Desativar prévia" ScaleFiltering="Filtragem de escala" ScaleFiltering.Point="Ponto" @@ -355,57 +356,63 @@ ScaleFiltering.Area="Área" Deinterlacing="Desentrelaçamento" Deinterlacing.Discard="Descartar" -Deinterlacing.Retro="Retro" -Deinterlacing.Blend="Misturar" -Deinterlacing.Blend2x="Misturar 2x" +Deinterlacing.Retro="Retrô" +Deinterlacing.Blend="Mistura" +Deinterlacing.Blend2x="Mistura 2x" Deinterlacing.Linear="Linear" Deinterlacing.Linear2x="Linear 2x" Deinterlacing.Yadif="Yadif" Deinterlacing.Yadif2x="Yadif 2x" -Deinterlacing.TopFieldFirst="Campo Superior Primeiro" -Deinterlacing.BottomFieldFirst="Campo Inferior Primeiro" +Deinterlacing.TopFieldFirst="Campo superior primeiro" +Deinterlacing.BottomFieldFirst="Campo inferior primeiro" -VolControl.SliderUnmuted="Barra de volume para '%1': %2" -VolControl.SliderMuted="Barra de volume para '%1': %2 (atualmente silenciado)" +VolControl.SliderUnmuted="Barra de volume para '%1':" +VolControl.SliderMuted="Barra de volume para '%1': (atualmente silenciado)" VolControl.Mute="Silenciar '%1'" VolControl.Properties="Propriedades de '%1'" -Basic.Main.AddSceneDlg.Title="Adicionar Cena" +Basic.Main.AddSceneDlg.Title="Adicionar cena" Basic.Main.AddSceneDlg.Text="Por favor, digite o nome da cena" Basic.Main.DefaultSceneName.Text="Cena %1" -Basic.Main.AddSceneCollection.Title="Adicionar Coleção de Cenas" -Basic.Main.AddSceneCollection.Text="Por favor, insira o nome da coleção de cena" +Basic.Main.AddSceneCollection.Title="Adicionar coleção de cenas" +Basic.Main.AddSceneCollection.Text="Por favor, insira o nome da coleção de cenas" -Basic.Main.RenameSceneCollection.Title="Renomear Coleção de Cenas" +Basic.Main.RenameSceneCollection.Title="Renomear coleção de cenas" AddProfile.Title="Adicionar perfil" AddProfile.Text="Por favor, insira o nome do perfil" +AddProfile.WizardCheckbox="Mostrar assistente de configuração" RenameProfile.Title="Renomear perfil" -Basic.Main.MixerRename.Title="Renomear Fonte de Áudio" +Basic.Main.MixerRename.Title="Renomear fonte de áudio" Basic.Main.MixerRename.Text="Por favor, digite o nome da fonte de áudio" Basic.Main.PreviewDisabled="A prévia está desativada" -Basic.SourceSelect="Criar/Selecionar Fonte" -Basic.SourceSelect.CreateNew="Criar Nova" -Basic.SourceSelect.AddExisting="Adicionar Existente" -Basic.SourceSelect.AddVisible="Tornar a Fonte visível" +Basic.SourceSelect="Criar ou reutilizar fonte" +Basic.SourceSelect.CreateNew="Criar nova" +Basic.SourceSelect.AddExisting="Reutilizar existente" +Basic.SourceSelect.AddVisible="Tornar a fonte visível" -Basic.PropertiesWindow="Propriedades para '%1'" +Basic.Main.Sources.Visibility="Visibilidade" +Basic.Main.Sources.VisibilityDescription="Controla a visibilidade de '%1' na tela" +Basic.Main.Sources.Lock="Bloquear" +Basic.Main.Sources.LockDescription="Bloqueia a posição e a escala de '%1' na tela" + +Basic.PropertiesWindow="Propriedades de '%1'" Basic.PropertiesWindow.AutoSelectFormat="%1 (seleção automática: %2)" -Basic.PropertiesWindow.SelectColor="Selecione uma cor" -Basic.PropertiesWindow.SelectFont="Selecionar Fonte" +Basic.PropertiesWindow.SelectColor="Escolher cor" +Basic.PropertiesWindow.SelectFont="Escolher fonte" 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.AddURL="Adicionar caminho ou URL" Basic.PropertiesWindow.AddEditableListDir="Adicionar pasta para '%1'" Basic.PropertiesWindow.AddEditableListFiles="Adicionar arquivos para '%1'" Basic.PropertiesWindow.AddEditableListEntry="Adicionar entrada a '%1'" @@ -418,7 +425,7 @@ Basic.PropertiesView.FPS.ValidFPSRanges="Intervalos de FPS válidos:" Basic.InteractionWindow="Interagindo com '%1'" Basic.StatusBar.Reconnecting="Desconectado, reconectando-se em %2 segundo(s) (tentativa %1)" -Basic.StatusBar.AttemptingReconnect="Tentando se reconectar... (tentativa %1)" +Basic.StatusBar.AttemptingReconnect="Tentando reconectar... (tentativa %1)" Basic.StatusBar.ReconnectSuccessful="Reconexão bem-sucedida" Basic.StatusBar.Delay="Atraso (%1 seg)" Basic.StatusBar.DelayStartingIn="Atraso (começando em %1 seg)" @@ -429,7 +436,7 @@ Basic.Filters="Filtros" Basic.Filters.AsyncFilters="Filtros de áudio/vídeo" Basic.Filters.AudioFilters="Filtros de áudio" Basic.Filters.EffectFilters="Filtros de efeito" -Basic.Filters.Title="Filtros para '%1'" +Basic.Filters.Title="Filtros de '%1'" Basic.Filters.AddFilter.Title="Nome do filtro" Basic.Filters.AddFilter.Text="Por favor, especifique o nome do filtro" @@ -437,131 +444,131 @@ Basic.TransformWindow="Transformação de elemento da cena" Basic.TransformWindow.Position="Posição" Basic.TransformWindow.Rotation="Rotação" Basic.TransformWindow.Size="Tamanho" -Basic.TransformWindow.Alignment="Alinhamento da Posição" +Basic.TransformWindow.Alignment="Alinhamento" Basic.TransformWindow.BoundsType="Tipo da caixa delimitadora" Basic.TransformWindow.BoundsAlignment="Alinhamento na caixa delimitadora" -Basic.TransformWindow.Bounds="Tamanho da Caixa Delimitadora" +Basic.TransformWindow.Bounds="Tamanho da caixa delimitadora" Basic.TransformWindow.Crop="Cortar" Basic.TransformWindow.Alignment.TopLeft="Superior esquerdo" -Basic.TransformWindow.Alignment.TopCenter="Superior Central" -Basic.TransformWindow.Alignment.TopRight="Superior Direito" -Basic.TransformWindow.Alignment.CenterLeft="Centro Esquerda" -Basic.TransformWindow.Alignment.Center="Centralizar" -Basic.TransformWindow.Alignment.CenterRight="Centro Direito" -Basic.TransformWindow.Alignment.BottomLeft="Inferior Esquerdo" -Basic.TransformWindow.Alignment.BottomCenter="Inferior Centro" -Basic.TransformWindow.Alignment.BottomRight="Inferior Direito" +Basic.TransformWindow.Alignment.TopCenter="Superior ao centro" +Basic.TransformWindow.Alignment.TopRight="Superior direito" +Basic.TransformWindow.Alignment.CenterLeft="Centro à esquerda" +Basic.TransformWindow.Alignment.Center="Centro" +Basic.TransformWindow.Alignment.CenterRight="Centro à direita" +Basic.TransformWindow.Alignment.BottomLeft="Inferior esquerdo" +Basic.TransformWindow.Alignment.BottomCenter="Inferior ao centro" +Basic.TransformWindow.Alignment.BottomRight="Inferior direito" -Basic.TransformWindow.BoundsType.None="Sem Bordas" -Basic.TransformWindow.BoundsType.MaxOnly="Apenas Tamanho Máximo" -Basic.TransformWindow.BoundsType.ScaleInner="Escalar até às bordas internas" -Basic.TransformWindow.BoundsType.ScaleOuter="Escalar até às bordas externas" -Basic.TransformWindow.BoundsType.ScaleToWidth="Escalar até à largura das bordas" -Basic.TransformWindow.BoundsType.ScaleToHeight="Escalar até à altura das bordas" -Basic.TransformWindow.BoundsType.Stretch="Esticar até às bordas" +Basic.TransformWindow.BoundsType.None="Sem bordas" +Basic.TransformWindow.BoundsType.MaxOnly="Apenas tamanho máximo" +Basic.TransformWindow.BoundsType.ScaleInner="Redimensionar até as bordas internas" +Basic.TransformWindow.BoundsType.ScaleOuter="Redimensionar até as bordas externas" +Basic.TransformWindow.BoundsType.ScaleToWidth="Redimensionar até a largura das bordas" +Basic.TransformWindow.BoundsType.ScaleToHeight="Redimensionar até a altura das bordas" +Basic.TransformWindow.BoundsType.Stretch="Esticar até as bordas" -Basic.Main.AddSourceHelp.Title="Não é Possível Adicionar Fonte" -Basic.Main.AddSourceHelp.Text="Precisa de pelo menos uma cena para adicionar uma fonte." +Basic.Main.AddSourceHelp.Title="Não foi possível adicionar a fonte" +Basic.Main.AddSourceHelp.Text="É necessário pelo menos uma cena para adicionar uma fonte." Basic.Main.Scenes="Cenas" Basic.Main.Sources="Fontes" Basic.Main.Controls="Controles" Basic.Main.Connecting="Conectando..." Basic.Main.StartRecording="Iniciar gravação" -Basic.Main.StartReplayBuffer="Iniciar Buffer do Replay" -Basic.Main.SaveReplay="Salvar Replay" +Basic.Main.StartReplayBuffer="Iniciar buffer de repetição" +Basic.Main.SaveReplay="Salvar replay" Basic.Main.StartStreaming="Iniciar transmissão" -Basic.Main.StartVirtualCam="Iniciar Câmera Virtual" -Basic.Main.StopRecording="Parar Gravação" -Basic.Main.PauseRecording="Pausar Gravação" -Basic.Main.UnpauseRecording="Continuar Gravação" -Basic.Main.StoppingRecording="Parando de Gravar..." -Basic.Main.StopReplayBuffer="Parar Buffer do Replay" -Basic.Main.StoppingReplayBuffer="Parando Buffer do Replay..." +Basic.Main.StartVirtualCam="Iniciar câmera virtual" +Basic.Main.StopRecording="Interromper gravação" +Basic.Main.PauseRecording="Pausar gravação" +Basic.Main.UnpauseRecording="Continuar gravação" +Basic.Main.StoppingRecording="Interrompendo gravação..." +Basic.Main.StopReplayBuffer="Interromper buffer de repetição" +Basic.Main.StoppingReplayBuffer="Interrompendo buffer de repetição..." Basic.Main.StopStreaming="Interromper transmissão" Basic.Main.StoppingStreaming="Interrompendo a transmissão..." -Basic.Main.ForceStopStreaming="Pare de transmitir (descartar atraso)" +Basic.Main.ForceStopStreaming="Interromper transmissão (ignorar atraso)" Basic.Main.ShowContextBar="Mostrar barra de ferramentas da fonte" Basic.Main.HideContextBar="Ocultar barra de ferramentas da fonte" -Basic.Main.StopVirtualCam="Parar Câmera Virtual" +Basic.Main.StopVirtualCam="Interromper câmera virtual" Basic.Main.Group="Grupo %1" -Basic.Main.GroupItems="Agrupar Itens Selecionados" +Basic.Main.GroupItems="Agrupar itens selecionados" Basic.Main.Ungroup="Desagrupar" -Basic.Main.GridMode="Modo Grade" -Basic.Main.ListMode="Modo Lista" +Basic.Main.GridMode="Modo grade" +Basic.Main.ListMode="Modo lista" Basic.MainMenu.File="Arquivo (&F)" Basic.MainMenu.File.Export="&Exportar" Basic.MainMenu.File.Import="&Importar" -Basic.MainMenu.File.ShowRecordings="Most&rar Gravações" +Basic.MainMenu.File.ShowRecordings="Mostrar g&ravações" Basic.MainMenu.File.Remux="Converter gravações (&M)" Basic.MainMenu.File.Settings="Configuraçõe&s" Basic.MainMenu.File.ShowSettingsFolder="Mostrar pasta de configurações" -Basic.MainMenu.File.ShowProfileFolder="Mostrar pasta de perfil" -Basic.MainMenu.AlwaysOnTop="Sempre no Topo (&A)" -Basic.MainMenu.File.Exit="Sair (&X)" +Basic.MainMenu.File.ShowProfileFolder="Mostrar pasta de perfis" +Basic.MainMenu.AlwaysOnTop="Sempre no topo (&A)" +Basic.MainMenu.File.Exit="Encerrar OBS (&X)" Basic.MainMenu.Edit="&Editar" Basic.MainMenu.Edit.Undo="Desfazer (&U)" Basic.MainMenu.Edit.Redo="&Refazer" Basic.MainMenu.Edit.UndoAction="Desfazer $1 (&U)" Basic.MainMenu.Edit.RedoAction="&Refazer $1" -Basic.MainMenu.Edit.LockPreview="B&loquear Prévia" -Basic.MainMenu.Edit.Scale="Vi&sualização e dimensionamento" -Basic.MainMenu.Edit.Scale.Window="Escala para janela" -Basic.MainMenu.Edit.Scale.Canvas="Lona (%1x%2)" +Basic.MainMenu.Edit.LockPreview="B&loquear prévia" +Basic.MainMenu.Edit.Scale="Tamanho da prévia (&S)" +Basic.MainMenu.Edit.Scale.Window="Dimensionar à janela" +Basic.MainMenu.Edit.Scale.Canvas="Tela (%1x%2)" Basic.MainMenu.Edit.Scale.Output="Saída (%1x%2)" Basic.MainMenu.Edit.Transform="&Transformar" -Basic.MainMenu.Edit.Transform.EditTransform="&Editar Transformação..." -Basic.MainMenu.Edit.Transform.CopyTransform="Copiar Transformação" -Basic.MainMenu.Edit.Transform.PasteTransform="Colar e transformar" -Basic.MainMenu.Edit.Transform.ResetTransform="Limpa&r Transformação" -Basic.MainMenu.Edit.Transform.Rotate90CW="Girar 90º sentido Horário" -Basic.MainMenu.Edit.Transform.Rotate90CCW="Girar 90º sentido Anti-Horário" +Basic.MainMenu.Edit.Transform.EditTransform="&Editar transformação..." +Basic.MainMenu.Edit.Transform.CopyTransform="Copiar transformação" +Basic.MainMenu.Edit.Transform.PasteTransform="Colar transformação" +Basic.MainMenu.Edit.Transform.ResetTransform="Limpa&r transformação" +Basic.MainMenu.Edit.Transform.Rotate90CW="Girar 90º sentido horário" +Basic.MainMenu.Edit.Transform.Rotate90CCW="Girar 90º sentido anti-horário" Basic.MainMenu.Edit.Transform.Rotate180="Girar 180º" -Basic.MainMenu.Edit.Transform.FlipHorizontal="Inverter &Horizontalmente" -Basic.MainMenu.Edit.Transform.FlipVertical="Inverter &Verticalmente" -Basic.MainMenu.Edit.Transform.FitToScreen="Ajustar à Tela (&F)" -Basic.MainMenu.Edit.Transform.StretchToScreen="E&stender à Tela" -Basic.MainMenu.Edit.Transform.CenterToScreen="&Centralizar à Tela" -Basic.MainMenu.Edit.Transform.VerticalCenter="Centralizar Verticalmente" -Basic.MainMenu.Edit.Transform.HorizontalCenter="Centralizar Horizontalmente" +Basic.MainMenu.Edit.Transform.FlipHorizontal="Inverter na &horizontal" +Basic.MainMenu.Edit.Transform.FlipVertical="Inverter na &vertical" +Basic.MainMenu.Edit.Transform.FitToScreen="Ajustar à tela (&F)" +Basic.MainMenu.Edit.Transform.StretchToScreen="E&stender à tela" +Basic.MainMenu.Edit.Transform.CenterToScreen="&Centralizar à tela" +Basic.MainMenu.Edit.Transform.VerticalCenter="Centralizar na vertical" +Basic.MainMenu.Edit.Transform.HorizontalCenter="Centralizar na horizontal" Basic.MainMenu.Edit.Order="&Ordem" -Basic.MainMenu.Edit.Order.MoveUp="Mover para Cima (&U)" -Basic.MainMenu.Edit.Order.MoveDown="Mover para Baixo (&D)" -Basic.MainMenu.Edit.Order.MoveToTop="Mover para o &Topo" -Basic.MainMenu.Edit.Order.MoveToBottom="Mover para a &Base" -Basic.MainMenu.Edit.AdvAudio="Propried&ades de áudio avançadas" +Basic.MainMenu.Edit.Order.MoveUp="Mover para cima (&U)" +Basic.MainMenu.Edit.Order.MoveDown="Mover para baixo (&D)" +Basic.MainMenu.Edit.Order.MoveToTop="Mover para o &topo" +Basic.MainMenu.Edit.Order.MoveToBottom="Mover para o fundo (&B)" +Basic.MainMenu.Edit.AdvAudio="Propriedades de áudio &avançadas" -Basic.MainMenu.View="Mostrar (&V)" -Basic.MainMenu.View.Toolbars="Barras de Ferramen&tas" -Basic.MainMenu.View.Docks="Docas" -Basic.MainMenu.View.Docks.ResetUI="Redefinir IU" -Basic.MainMenu.View.Docks.LockUI="Travar IU" -Basic.MainMenu.View.Docks.CustomBrowserDocks="Docas para Navegador Personalizado..." -Basic.MainMenu.View.ListboxToolbars="Botões da Lista de Cena/Origem" -Basic.MainMenu.View.ContextBar="Barra de ferramenta das fontes" -Basic.MainMenu.View.SceneTransitions="Transições de &Cena" -Basic.MainMenu.View.SourceIcons="Ícones em Fontes (&I)" -Basic.MainMenu.View.StatusBar="Barra de &Status" -Basic.MainMenu.View.Fullscreen.Interface="Interface em Tela Cheia" +Basic.MainMenu.View="&Visualizar" +Basic.MainMenu.View.Toolbars="Barras de ferramen&tas" +Basic.MainMenu.View.Docks="Abas" +Basic.MainMenu.View.Docks.ResetUI="Redefinir interface" +Basic.MainMenu.View.Docks.LockUI="Travar interface" +Basic.MainMenu.View.Docks.CustomBrowserDocks="Abas personalizáveis com URL..." +Basic.MainMenu.View.ListboxToolbars="Botões da lista de cena/origem" +Basic.MainMenu.View.ContextBar="Barra de ferramentas da fonte" +Basic.MainMenu.View.SceneTransitions="Transições de &cena" +Basic.MainMenu.View.SourceIcons="Ícones em fontes (&I)" +Basic.MainMenu.View.StatusBar="Barra de &status" +Basic.MainMenu.View.Fullscreen.Interface="Interface em tela cheia" -Basic.MainMenu.SceneCollection="Coleção de Cena&s" +Basic.MainMenu.SceneCollection="Coleção de cena&s" Basic.MainMenu.Profile="&Perfil" -Basic.MainMenu.Profile.Import="Importar Perfil" -Basic.MainMenu.Profile.Export="Exportar Perfil" -Basic.MainMenu.SceneCollection.Import="Importar Coleção de Cenas" -Basic.MainMenu.SceneCollection.Export="Exportar Coleção de Cenas" -Basic.MainMenu.Profile.Exists="Perfil já existe" -Basic.MainMenu.SceneCollection.Exists="A coleção de cenas já existe" +Basic.MainMenu.Profile.Import="Importar perfil" +Basic.MainMenu.Profile.Export="Exportar perfil" +Basic.MainMenu.SceneCollection.Import="Importar coleção de cenas" +Basic.MainMenu.SceneCollection.Export="Exportar coleção de cenas" +Basic.MainMenu.Profile.Exists="Esse perfil já existe" +Basic.MainMenu.SceneCollection.Exists="Essa coleção de cenas já existe" Basic.MainMenu.Tools="Ferramentas (&T)" Basic.MainMenu.Help="Ajuda (&H)" -Basic.MainMenu.Help.HelpPortal="&Portal de Ajuda" +Basic.MainMenu.Help.HelpPortal="&Portal de ajuda" Basic.MainMenu.Help.Website="Visitar &website" -Basic.MainMenu.Help.Discord="Juntar-se ao Servidor do &Discord" +Basic.MainMenu.Help.Discord="Entrar no servidor do &Discord" Basic.MainMenu.Help.Logs="Arquivos de registro (&L)" Basic.MainMenu.Help.Logs.ShowLogs="Mo&strar arquivos de registro" Basic.MainMenu.Help.Logs.UploadCurrentLog="&Carregar arquivo de registro atual" @@ -573,41 +580,41 @@ Basic.MainMenu.Help.CrashLogs.ShowLogs="Mo&strar relatórios de erros" Basic.MainMenu.Help.CrashLogs.UploadLastLog="Carregar ú<imo relatório de erros" Basic.MainMenu.Help.About="Sobre (&A)" -Basic.Settings.ProgramRestart="O Programa precisar ser reiniciado para que estas configurações surtam efeito." -Basic.Settings.ConfirmTitle="Confirmar Alterações" -Basic.Settings.Confirm="Você tem alterações não salvas. Salvar as alterações?" +Basic.Settings.ProgramRestart="Reinicie o programa para aplicar as configurações." +Basic.Settings.ConfirmTitle="Confirmar alterações" +Basic.Settings.Confirm="Há alterações não salvas. Deseja salvar agora?" Basic.Settings.General="Geral" Basic.Settings.General.Theme="Tema" Basic.Settings.General.Language="Idioma" -Basic.Settings.General.EnableAutoUpdates="Buscar novas atualizações ao iniciar o programa" -Basic.Settings.General.OpenStatsOnStartup="Abrir janela de estatísticas na inicialização" -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.WarnBeforeStoppingRecord="Mostrar diálogo de confirmação ao parar a gravação" +Basic.Settings.General.EnableAutoUpdates="Buscar novas atualizações ao inicializar" +Basic.Settings.General.OpenStatsOnStartup="Abrir janela de estatísticas ao inicializar" +Basic.Settings.General.WarnBeforeStartingStream="Perguntar antes de iniciar transmissões" +Basic.Settings.General.WarnBeforeStoppingStream="Perguntar antes de interromper transmissões" +Basic.Settings.General.WarnBeforeStoppingRecord="Perguntar antes de interromper gravações" Basic.Settings.General.Projectors="Projetores" 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.Snapping="Encaixe das fontes na tela" +Basic.Settings.General.ScreenSnapping="Encaixar fontes nas bordas da tela" +Basic.Settings.General.CenterSnapping="Encaixar fontes no centro horizontal e vertical" Basic.Settings.General.SourceSnapping="Encaixar fontes com outras fontes" -Basic.Settings.General.SnapDistance="Sensibilidade de Encaixamento" +Basic.Settings.General.SnapDistance="Sensibilidade do encaixe" Basic.Settings.General.RecordWhenStreaming="Gravar automaticamente quando estiver transmitindo" Basic.Settings.General.KeepRecordingWhenStreamStops="Continuar gravando quando a transmissão parar" Basic.Settings.General.ReplayBufferWhileStreaming="Iniciar automaticamente o buffer de repetição durante a transmissão" Basic.Settings.General.KeepReplayBufferStreamStops="Manter o buffer de repetição ativo quando a transmissão parar" -Basic.Settings.General.SysTray="Bandeja do sistema" -Basic.Settings.General.SysTrayWhenStarted="Minimizar para a bandeja do sistema quando iniciar" +Basic.Settings.General.SysTray="Barra do sistema" +Basic.Settings.General.SysTrayWhenStarted="Minimizar para a barra do sistema quando começar" Basic.Settings.General.SystemTrayHideMinimize="Sempre minimizar para a bandeja (ignorar barra de tarefas)" -Basic.Settings.General.SaveProjectors="Salvar projetores ao sair" +Basic.Settings.General.SaveProjectors="Salvar projetores ao encerrar" Basic.Settings.General.Preview="Prévia" Basic.Settings.General.OverflowHidden="Esconder excesso" Basic.Settings.General.OverflowAlwaysVisible="Excesso sempre visível" Basic.Settings.General.OverflowSelectionHidden="Mostrar excesso mesmo quando a fonte estiver escondida" Basic.Settings.General.Importers="Importadores" Basic.Settings.General.AutomaticCollectionSearch="Procurar em locais conhecidos por coleções de cena ao importar" -Basic.Settings.General.SwitchOnDoubleClick="Mudar para a cena quando clicar duas vezes" +Basic.Settings.General.SwitchOnDoubleClick="Usar transição para a cena quando clicar duas vezes" Basic.Settings.General.StudioPortraitLayout="Ativar a disposição horizontal/vertical" Basic.Settings.General.TogglePreviewProgramLabels="Mostrar rótulos de prévia/programa" Basic.Settings.General.Multiview="Visualização múltipla" @@ -627,85 +634,97 @@ Basic.Settings.Stream.Custom.UseAuthentication="Utilizar autenticação" Basic.Settings.Stream.Custom.Username="Nome de usuário" Basic.Settings.Stream.Custom.Password="Senha" Basic.Settings.Stream.BandwidthTestMode="Ativar modo de teste de largura de banda" -Basic.Settings.Stream.TTVAddon="Complementos de bate-papo do Twitch" +Basic.Settings.Stream.TTVAddon="Complementos do chat da Twitch" Basic.Settings.Stream.TTVAddon.None="Nenhum" Basic.Settings.Stream.TTVAddon.Both="BetterTTV e FrankerFaceZ" -Basic.Settings.Stream.MissingSettingAlert="Configuração do Stream Incompleta" -Basic.Settings.Stream.StreamSettingsWarning="Abrir Configurações" -Basic.Settings.Stream.MissingUrlAndApiKey="O URL e a Chave de Transmissão estão em branco.\n\nAbra as configurações e insira a chave de transmissão e a URL na aba 'Transmissão'." -Basic.Settings.Stream.MissingUrl="URL da transmissão está em branco.\n\nAbra as configurações para inserir a URL na aba 'Transmissão'." -Basic.Settings.Stream.MissingStreamKey="Chave de transmissão está em branco.\n\nAbra as configurações para inserir a Chave de Transmissão na aba 'Transmissão'." +Basic.Settings.Stream.MissingSettingAlert="Configuração incompleta" +Basic.Settings.Stream.StreamSettingsWarning="Abrir configurações" +Basic.Settings.Stream.MissingUrlAndApiKey="A URL e a chave de transmissão estão em branco.\n\nAbra as configurações e insira-os na aba 'Transmissão'." +Basic.Settings.Stream.MissingUrl="A URL da transmissão está em branco.\n\nAbra as configurações e insira a URL na aba 'Transmissão'." +Basic.Settings.Stream.MissingStreamKey="A chave de transmissão está em branco.\n\nAbra as configurações e insira a chave de transmissão na aba 'Transmissão'." +Basic.Settings.Stream.IgnoreRecommended="Ignorar recomendações de configuração do serviço de streaming" +Basic.Settings.Stream.IgnoreRecommended.Warn.Title="Sobrepor configurações recomendadas" +Basic.Settings.Stream.IgnoreRecommended.Warn.Text="Aviso: ignorar limitações do serviço pode impedir ou reduzir a qualidade da sua transmissão.\n\nContinuar?" +Basic.Settings.Stream.Recommended.MaxVideoBitrate="Taxa de bits máxima de vídeo: %1 kbps" +Basic.Settings.Stream.Recommended.MaxAudioBitrate="Taxa de bits máxima de áudio: %1 kbps" +Basic.Settings.Stream.Recommended.MaxResolution="Resolução máxima: %1" +Basic.Settings.Stream.Recommended.MaxFPS="Taxa de quadros máxima: %1" Basic.Settings.Output="Saída" Basic.Settings.Output.Format="Formato de gravação" -Basic.Settings.Output.Encoder="Encoder" -Basic.Settings.Output.SelectDirectory="Selecione o diretório de gravação" +Basic.Settings.Output.Encoder="Codificador" +Basic.Settings.Output.SelectDirectory="Selecione a pasta de gravação" Basic.Settings.Output.SelectFile="Selecione o arquivo de gravação" -Basic.Settings.Output.EnforceBitrate="Impor limites de bitrate do serviço de transmissão" Basic.Settings.Output.DynamicBitrate="Alterar taxa de bits dinamicamente para gerenciar o congestionamento" -Basic.Settings.Output.DynamicBitrate.Beta="Alterar taxa de bits dinamicamente para gerenciar o congestionamento (Beta)" -Basic.Settings.Output.DynamicBitrate.TT="Em vez de derrubar os quadros para reduzir o congestionamento, mudanças dinâmicas na taxa de bits durante o processo.\n\nNote que isso pode aumentar o atraso para os espectadores se houver um congestionamento repentino significativo.\nQuando a taxa de bits cair, pode levar até alguns minutos para restaurar.\n\nAtualmente suportado apenas para RTMP." -Basic.Settings.Output.Mode="Modo de Saída" +Basic.Settings.Output.DynamicBitrate.Beta="Alterar taxa de bits dinamicamente para gerenciar o congestionamento (beta)" +Basic.Settings.Output.DynamicBitrate.TT="Altera dinamicamente a taxa de bits em tempo real, em vez de perder frames para reduzir o congestionamento.\n\nNote que isso pode aumentar o atraso para os espectadores se houver um congestionamento repentino significativo.\nQuando a taxa de bits cair, pode levar até alguns minutos para restaurar.\n\nAtualmente suportado apenas para RTMP." +Basic.Settings.Output.Mode="Modo de saída" Basic.Settings.Output.Mode.Simple="Simples" Basic.Settings.Output.Mode.Adv="Avançado" Basic.Settings.Output.Mode.FFmpeg="Saída de FFmpeg" -Basic.Settings.Output.UseReplayBuffer="Habilitar Buffer de Repetição" -Basic.Settings.Output.ReplayBuffer.SecondsMax="Tempo máximo de repetição" -Basic.Settings.Output.ReplayBuffer.MegabytesMax="Memória Máxima (Megabytes)" +Basic.Settings.Output.UseReplayBuffer="Habilitar buffer de repetição" +Basic.Settings.Output.ReplayBuffer.SecondsMax="Tempo máximo do replay" +Basic.Settings.Output.ReplayBuffer.MegabytesMax="Máximo de memória (megabytes)" Basic.Settings.Output.ReplayBuffer.Estimate="Uso de memória estimado: %1 MB" -Basic.Settings.Output.ReplayBuffer.EstimateUnknown="Impossível estimar o uso de memória. Por favor, defina o limite máximo de memória." -Basic.Settings.Output.ReplayBuffer.Prefix="Prefixo do Buffer de Repetição" +Basic.Settings.Output.ReplayBuffer.EstimateUnknown="Não foi possível estimar o uso de memória. Por favor, defina o limite máximo de memória." +Basic.Settings.Output.ReplayBuffer.Prefix="Prefixo do buffer de repetição" Basic.Settings.Output.ReplayBuffer.Suffix="Sufixo" Basic.Settings.Output.Simple.SavePath="Caminho de gravação" Basic.Settings.Output.Simple.RecordingQuality="Qualidade da gravação" Basic.Settings.Output.Simple.RecordingQuality.Stream="A mesma da transmissão" -Basic.Settings.Output.Simple.RecordingQuality.Small="Alta qualidade, tamanho médio" -Basic.Settings.Output.Simple.RecordingQuality.HQ="Qualidade indistinguível, Tamanho grande" -Basic.Settings.Output.Simple.RecordingQuality.Lossless="Qualidade Lossless, tremendamente grande" -Basic.Settings.Output.Simple.Warn.VideoBitrate="Aviso: O bitrate de vídeo da transmissão será definido para %1, que é o limite superior para o serviço de transmissão atual. Se você tem certeza que quer ir acima de %1, habilite opções de codificação avançadas e desmarque \"Impor limites de bitrate do serviço de transmissão\"." -Basic.Settings.Output.Simple.Warn.AudioBitrate="Aviso: O bitrate de áudio da transmissão será definido para %1, que é o limite superior para o serviço de transmissão atual. Se você tem certeza que quer ir acima de %1, habilite opções de codificação avançadas e desmarque \"Impor limites de bitrate do serviço de transmissão\"." -Basic.Settings.Output.Simple.Warn.CannotPause="Aviso: Gravações não podem ser pausadas se a qualidade da gravação estiver definida como \"A mesma da transmissão\"." -Basic.Settings.Output.Simple.Warn.Encoder="Aviso: Gravar com um codificador de software em uma qualidade diferente do que a stream vai exigir mais da CPU se você transmitir e gravar ao mesmo tempo." -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.RecordingQuality.Small="Qualidade alta, arquivo normal" +Basic.Settings.Output.Simple.RecordingQuality.HQ="Qualidade muito boa, arquivo pesado" +Basic.Settings.Output.Simple.RecordingQuality.Lossless="Sem perda de qualidade, arquivo muito pesado" +Basic.Settings.Output.Simple.Warn.VideoBitrate="Aviso: a taxa de bits do vídeo transmitido será definida como %1, que é o limite máximo para o serviço de transmissão atual." +Basic.Settings.Output.Simple.Warn.AudioBitrate="Aviso: a taxa de bits do áudio transmitido será definida como %1, que é o limite máximo para o serviço de transmissão atual." +Basic.Settings.Output.Simple.Warn.CannotPause="Aviso: gravações não podem ser pausadas se a qualidade da gravação estiver definida como \"A mesma da transmissão\"." +Basic.Settings.Output.Simple.Warn.Encoder="Aviso: gravar com um codificador de software em uma qualidade diferente da transmissão vai exigir mais da CPU se você transmitir e gravar ao mesmo tempo." +Basic.Settings.Output.Simple.Warn.Lossless="Aviso: o modo sem perda de qualidade gera arquivos muito grandes, que podem usar mais de 7 gigabytes de espaço em disco por minuto em altas resoluções e taxas de quadros. Modo sem perdas não é recomendado 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="Deseja mesmo usar a qualidade sem perdas?" +Basic.Settings.Output.Simple.Warn.Lossless.Title="Aviso de qualidade muito alta!" 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 (preset x264 de baixa utilização de CPU, aumenta o tamanho do arquivo)" -Basic.Settings.Output.VideoBitrate="Taxa de Bits do Vídeo" -Basic.Settings.Output.AudioBitrate="Taxa de Bits do Áudio" +Basic.Settings.Output.Simple.TwitchVodTrack="Faixa de VOD da Twitch (Usa faixa 2)" +Basic.Settings.Output.Warn.EnforceResolutionFPS.Title="Resolução ou taxa de quadros incompatíveis" +Basic.Settings.Output.Warn.EnforceResolutionFPS.Msg="Este serviço de streaming não suporta sua atual resolução e/ou taxa de quadros de saída. Eles serão alterados para o valor compatível mais próximo:\n\n%1\n\nVocê deseja continuar?" +Basic.Settings.Output.Warn.EnforceResolutionFPS.Resolution="Resolução: %1" +Basic.Settings.Output.Warn.EnforceResolutionFPS.FPS="Taxa de quadros: %1" +Basic.Settings.Output.VideoBitrate="Taxa de bits do vídeo" +Basic.Settings.Output.AudioBitrate="Taxa de bits do áudio" Basic.Settings.Output.Reconnect="Reconectar automaticamente" Basic.Settings.Output.RetryDelay="Atraso de repetição" -Basic.Settings.Output.MaxRetries="Número Máximo de Tentativas" +Basic.Settings.Output.MaxRetries="Número máximo de tentativas" Basic.Settings.Output.Advanced="Ativar as configurações avançadas do encoder" -Basic.Settings.Output.EncoderPreset="Padrão de Codificação" +Basic.Settings.Output.EncoderPreset="Padrão de codificação" Basic.Settings.Output.CustomEncoderSettings="Configurações de codificador personalizadas" Basic.Settings.Output.CustomMuxerSettings="Configurações personalizadas do Muxer" -Basic.Settings.Output.NoSpaceFileName="Gerar Nome de Arquivo sem Espaços" +Basic.Settings.Output.NoSpaceFileName="Gerar nome de arquivo sem espaços" Basic.Settings.Output.Adv.Rescale="Redimensionar a saída" Basic.Settings.Output.Adv.AudioTrack="Faixa de áudio" Basic.Settings.Output.Adv.Streaming="Transmissão" -Basic.Settings.Output.Adv.ApplyServiceSettings="Impor configurações do serviço de codificador de transmissão" Basic.Settings.Output.Adv.Audio.Track1="Faixa 1" Basic.Settings.Output.Adv.Audio.Track2="Faixa 2" Basic.Settings.Output.Adv.Audio.Track3="Faixa 3" Basic.Settings.Output.Adv.Audio.Track4="Faixa 4" Basic.Settings.Output.Adv.Audio.Track5="Faixa 5" Basic.Settings.Output.Adv.Audio.Track6="Faixa 6" +Basic.Settings.Output.Adv.TwitchVodTrack="Faixa de VOD da Twitch" Basic.Settings.Output.Adv.Recording="Gravação" +Basic.Settings.Output.Adv.Recording.RecType="Tipo de gravação" Basic.Settings.Output.Adv.Recording.Type="Tipo" Basic.Settings.Output.Adv.Recording.Type.Standard="Padrão" Basic.Settings.Output.Adv.Recording.Type.FFmpegOutput="Saída personalizada (FFmpeg)" -Basic.Settings.Output.Adv.Recording.UseStreamEncoder="(Utilizar o codificador da transmissão)" -Basic.Settings.Output.Adv.Recording.Filename="Formatação de Nome de Arquivo" -Basic.Settings.Output.Adv.Recording.OverwriteIfExists="Substituir, se o arquivo existir" +Basic.Settings.Output.Adv.Recording.UseStreamEncoder="(Usar o codificador da transmissão)" +Basic.Settings.Output.Adv.Recording.Filename="Formatação do nome do arquivo" +Basic.Settings.Output.Adv.Recording.OverwriteIfExists="Sobrescrever caso o arquivo exista" Basic.Settings.Output.Adv.FFmpeg.Type="Tipo de saída FFmpeg" Basic.Settings.Output.Adv.FFmpeg.Type.URL="Saída para URL" -Basic.Settings.Output.Adv.FFmpeg.Type.RecordToFile="Exportar para arquivo" +Basic.Settings.Output.Adv.FFmpeg.Type.RecordToFile="Saída para um arquivo" Basic.Settings.Output.Adv.FFmpeg.SaveFilter.Common="Formatos de gravação comuns" Basic.Settings.Output.Adv.FFmpeg.SaveFilter.All="Todos os arquivos" Basic.Settings.Output.Adv.FFmpeg.SavePathURL="Caminho do arquivo ou URL" @@ -714,54 +733,54 @@ Basic.Settings.Output.Adv.FFmpeg.FormatAudio="Áudio" Basic.Settings.Output.Adv.FFmpeg.FormatVideo="Vídeo" Basic.Settings.Output.Adv.FFmpeg.FormatDefault="Formato padrão" Basic.Settings.Output.Adv.FFmpeg.FormatDesc="Descrição do formato do contêiner" -Basic.Settings.Output.Adv.FFmpeg.FormatDescDef="Codec de áudio/vídeo supostos do caminho do arquivo ou URL" +Basic.Settings.Output.Adv.FFmpeg.FormatDescDef="O codificador de áudio/vídeo é uma suposição a partir do arquivo ou URL" Basic.Settings.Output.Adv.FFmpeg.AVEncoderDefault="Codificador padrão" Basic.Settings.Output.Adv.FFmpeg.AVEncoderDisable="Desativar o codificador" Basic.Settings.Output.Adv.FFmpeg.VEncoder="Codificador de vídeo" -Basic.Settings.Output.Adv.FFmpeg.VEncoderSettings="Configurações do codificador de vídeo(se houver)" +Basic.Settings.Output.Adv.FFmpeg.VEncoderSettings="Configurações do codificador de vídeo (se houver)" Basic.Settings.Output.Adv.FFmpeg.AEncoder="Codificador de áudio" -Basic.Settings.Output.Adv.FFmpeg.AEncoderSettings="Configurações do codificador de áudio(se houver)" +Basic.Settings.Output.Adv.FFmpeg.AEncoderSettings="Configurações do codificador de áudio (se houver)" Basic.Settings.Output.Adv.FFmpeg.MuxerSettings="Configurações do Muxer (se houver)" -Basic.Settings.Output.Adv.FFmpeg.GOPSize="Intervalo de Keyframes (frames)" -Basic.Settings.Output.Adv.FFmpeg.IgnoreCodecCompat="Mostrar todos os codecs (incluir potencialmente incompatíveis)" +Basic.Settings.Output.Adv.FFmpeg.GOPSize="Intervalo de keyframes (quadros)" +Basic.Settings.Output.Adv.FFmpeg.IgnoreCodecCompat="Mostrar todos os codificadores (incluir potencialmente incompatíveis)" Screenshot="Caminho da captura de tela" -Screenshot.SourceHotkey="Capturar tela da fonte selecionada" -Screenshot.StudioProgram="Capturar tela (Programa)" -Screenshot.Preview="Capturar tela (Pré-visualização)" -Screenshot.Scene="Capturar tela (Cena)" -Screenshot.Source="Capturar tela (Fonte)" +Screenshot.SourceHotkey="Capturar fonte selecionada" +Screenshot.StudioProgram="Capturar tela (programa)" +Screenshot.Preview="Capturar tela (prévia)" +Screenshot.Scene="Capturar tela (cena)" +Screenshot.Source="Capturar tela (fonte)" 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\n%FPS\n%CRES\n%ORES\n%VF" -FilenameFormatting.TT="%CCYY Ano, quatro dígitos\n%YY Ano, últimos dois dígitos (00-99)\n%MM Mês como um número decimal (01-12)\n%DD Dia do mês, começando com 0 (01-31)\n%hh Hora, em formato de 24h (00-23)\n%mm Minuto (00-59)\n%ss Segundo (00-61)\n%% A % sign\n%a Dia da Semana abreviado\n%A Nome da Semana completo\n%b Nome do Mês abreviado\n%B Nome do Mês completo\n%d Dia do Mês, começando com 0 (01-31)\n%H Hora, no formato de 24h (00-23)\n%I Hora no formato de 12h (01-12)\n%m Mês como um número decimal (01-12)\n%M Minuto (00-59)\n%p Designação AM ou PM\n%S Segundo (00-61)\n%y Ano, últimos dois dígitos (00-99)\n%Y Ano\n%z diferença do UTC em fuso horários ISO 8601 \n%Z Nome do Fuso Horário ou abreviação\n%FPS Quadros por segundo\n%CRES Resolução de base (tela)\n%ORES Resolução de saída (escala)\n%VF Formato de Vídeo" +FilenameFormatting.TT="%CCYY Ano, quatro dígitos\n%YY Ano, últimos dois dígitos (00-99)\n%MM Mês como um número decimal (01-12)\n%DD Dia do mês, começando com 0 (01-31)\n%hh Hora, em formato de 24h (00-23)\n%mm Minuto (00-59)\n%ss Segundo (00-61)\n%% A % sign\n%a Dia da semana abreviado\n%A Nome da semana completo\n%b Nome do mês abreviado\n%B Nome do Mês completo\n%d Dia do mês, começando com 0 (01-31)\n%H Hora, no formato de 24h (00-23)\n%I Hora no formato de 12h (01-12)\n%m Mês como um número decimal (01-12)\n%M Minuto (00-59)\n%p Designação AM ou PM\n%S Segundo (00-61)\n%y Ano, últimos dois dígitos (00-99)\n%Y Ano\n%z Diferença do fuso horários no UTC pelo ISO 8601 \n%Z Nome do fuso horário ou abreviação\n%FPS Quadros por segundo\n%CRES Resolução de base (tela)\n%ORES Resolução de saída (escala)\n%VF Formato de vídeo" Basic.Settings.Video="Vídeo" -Basic.Settings.Video.Adapter="Adaptador de Vídeo" +Basic.Settings.Video.Adapter="Adaptador de vídeo" Basic.Settings.Video.BaseResolution="Resolução de base (tela)" Basic.Settings.Video.ScaledResolution="Resolução de saída (escala)" -Basic.Settings.Video.DownscaleFilter="Filtro de Redução" -Basic.Settings.Video.DisableAeroWindows="Desativar o Aero (somente Windows)" +Basic.Settings.Video.DownscaleFilter="Filtro de redução" +Basic.Settings.Video.DisableAeroWindows="Desativar Aero (somente Windows)" Basic.Settings.Video.FPS="FPS" -Basic.Settings.Video.FPSCommon="Valor de FPS Comum" -Basic.Settings.Video.FPSInteger="Valor de FPS Íntegro" -Basic.Settings.Video.FPSFraction="Valor de FPS Fracional" +Basic.Settings.Video.FPSCommon="Valores comuns de FPS" +Basic.Settings.Video.FPSInteger="Valores inteiros de FPS" +Basic.Settings.Video.FPSFraction="Valores fracionários de FPS" Basic.Settings.Video.Numerator="Numerador" -Basic.Settings.Video.Denominator="Demoninador" +Basic.Settings.Video.Denominator="Denominador" Basic.Settings.Video.Renderer="Renderizador" -Basic.Settings.Video.InvalidResolution="Resolução Inválida, Obrigatório ser [largura]x[altura] (ex. 1920x1080)" +Basic.Settings.Video.InvalidResolution="Resolução inválida. Precisa ser [largura]x[altura] (ex.: 1920x1080)" Basic.Settings.Video.CurrentlyActive="A saída de vídeo está atualmente ativa. Por favor, desligue quaisquer saídas para alterar as configurações de vídeo." Basic.Settings.Video.DisableAero="Desativar Aero" -Basic.Settings.Video.DownscaleFilter.Bilinear="Bilinear(rápido, mas embaçado se redimensionando)" -Basic.Settings.Video.DownscaleFilter.Bicubic="Bicúbico (escalamento nítido, 16 amostras)" -Basic.Settings.Video.DownscaleFilter.Lanczos="Lanczos (escalamento nítido, 36 amostras)" +Basic.Settings.Video.DownscaleFilter.Bilinear="Bilinear (mais rápido, porém embaça se redimensionado)" +Basic.Settings.Video.DownscaleFilter.Bicubic="Bicúbico (redimensionamento nítido, 16 amostras)" +Basic.Settings.Video.DownscaleFilter.Lanczos="Lanczos (redimensionamento nítido, 36 amostras)" Basic.Settings.Video.DownscaleFilter.Area="Área (soma ponderada, 4/6/9 amostras)" Basic.Settings.Audio="Áudio" -Basic.Settings.Audio.SampleRate="Taxa de Amostragem" +Basic.Settings.Audio.SampleRate="Taxa de amostragem" Basic.Settings.Audio.Channels="Canais" -Basic.Settings.Audio.Meters="Metros" +Basic.Settings.Audio.Meters="Métricas" Basic.Settings.Audio.MeterDecayRate="Taxa de decaimento" Basic.Settings.Audio.MeterDecayRate.Fast="Rápida" Basic.Settings.Audio.MeterDecayRate.Medium="Média (PPM Tipo I)" @@ -769,13 +788,13 @@ Basic.Settings.Audio.MeterDecayRate.Slow="Devagar (PPM Tipo II)" Basic.Settings.Audio.PeakMeterType="Tipo do medidor de pico" Basic.Settings.Audio.PeakMeterType.SamplePeak="Exemplo de pico" Basic.Settings.Audio.PeakMeterType.TruePeak="True Peak (Uso elevado de CPU)" -Basic.Settings.Audio.MultiChannelWarning.Enabled="AVISO: Áudio Surround está habilitado." +Basic.Settings.Audio.MultiChannelWarning.Enabled="AVISO: áudio Surround está ativado." Basic.Settings.Audio.MultichannelWarning="Antes de transmitir, verifique se o seu serviço de transmissão suporta tanto receber como reproduzir som surround. Facebook 360 Live é um exemplo onde o som surround é totalmente suportado. Embora o Facebook Live e o YouTube Live ambos aceitem receber som surround, o Facebook Live transformará para estéreo e o YouTube Live reproduz apenas dois canais.\n\nOs filtros de áudio do OBS são compatíveis com o som surround, embora o suporte do plugin VST não seja garantido." Basic.Settings.Audio.MultichannelWarning.Title="Ativar o som surround?" -Basic.Settings.Audio.MultichannelWarning.Confirm="Você tem certeza de que deseja habilitar o som surround?" -Basic.Settings.Audio.Devices="Dispositivos de Áudio Globais" -Basic.Settings.Audio.DesktopDevice="Áudio da Área de Trabalho" -Basic.Settings.Audio.DesktopDevice2="Áudio da Área de Trabalho 2" +Basic.Settings.Audio.MultichannelWarning.Confirm="Deseja mesmo ativar o som surround?" +Basic.Settings.Audio.Devices="Dispositivos de áudio globais" +Basic.Settings.Audio.DesktopDevice="Áudio do desktop" +Basic.Settings.Audio.DesktopDevice2="Áudio do desktop 2" Basic.Settings.Audio.AuxDevice="Dispositivo de Áudio Mic/Auxiliar" Basic.Settings.Audio.AuxDevice2="Dispositivo de áudio/microfone auxiliar 2" Basic.Settings.Audio.AuxDevice3="Dispositivo de áudio/microfone auxiliar 3" @@ -821,16 +840,21 @@ Basic.Settings.Advanced.AutoRemux="Converter automaticamente para mp4" Basic.Settings.Advanced.AutoRemux.MP4="(gravar como mkv)" Basic.AdvAudio="Propriedades de áudio avançadas" -Basic.AdvAudio.ActiveOnly="Apenas Fontes Ativas" +Basic.AdvAudio.ActiveOnly="Apenas fontes ativas" Basic.AdvAudio.Name="Nome" Basic.AdvAudio.Volume="Volume" +Basic.AdvAudio.VolumeSource="Volume para '%1'" Basic.AdvAudio.Mono="Mono" +Basic.AdvAudio.MonoSource="Downmix de mono para '%1'" Basic.AdvAudio.Balance="Balanço" -Basic.AdvAudio.SyncOffset="Sincronizar Offset" +Basic.AdvAudio.BalanceSource="Balanço para '%1'" +Basic.AdvAudio.SyncOffset="Sincronizar offset" +Basic.AdvAudio.SyncOffsetSource="Deslocamento de sincronização para '%1'" Basic.AdvAudio.Monitoring="Monitoramento de Áudio" Basic.AdvAudio.Monitoring.None="Não monitorar" Basic.AdvAudio.Monitoring.MonitorOnly="Apenas monitorar (saída muda)" Basic.AdvAudio.Monitoring.Both="Monitorar e enviar áudio" +Basic.AdvAudio.MonitoringSource="Monitoramento de Áudio para '%1'" Basic.AdvAudio.AudioTracks="Faixas" Basic.Settings.Hotkeys="Teclas de atalho" @@ -891,15 +915,15 @@ SceneItemHide="Ocultar '%1'" OutputWarnings.NoTracksSelected="Você deve selecionar pelo menos uma faixa" OutputWarnings.MP4Recording="Atenção: as gravações salvas em MP4/MOV não serão recuperáveis se o arquivo não puder ser concluído (por exemplo, como resultado de um BSOD, perdas de energia, etc.). Se você quiser gravar várias faixas de áudio, aconselhamos utilizar o MKV e, uma vez terminado, converter a gravação para MP4/MOV (Arquivo → Converter gravações)" -OutputWarnings.CannotPause="Aviso: As gravações não podem ser pausadas se o codificador de gravação estiver definido para \"(Utilizar o codificador da transmissão)\"" +OutputWarnings.CannotPause="Aviso: gravações não podem ser pausadas se o codificador de gravação estiver definido para \"(Usar o codificador da transmissão)\"" FinalScene.Title="Excluir cena" FinalScene.Text="É preciso haver pelo menos uma cena." -NoSources.Title="Sem Fontes" -NoSources.Text="Parece que você ainda não adicionou nenhuma fonte de vídeo, portanto, você só exibirá uma tela em branco. Você tem certeza de que quer fazer isso?" -NoSources.Text.AddSource="Você pode adicionar fontes clicando no ícone + sob a caixa de Fontes na janela principal, a qualquer momento." -NoSources.Label="Você não tem nenhuma fonte.\nClique no botão + abaixo,\nou clique direito aqui para adicionar uma." +NoSources.Title="Sem fontes" +NoSources.Text="Parece que você ainda não adicionou nenhuma fonte de vídeo, portanto, você só exibirá uma tela em branco. Deseja mesmo fazer isso?" +NoSources.Text.AddSource="Você pode adicionar fontes clicando no ícone + sob a aba de Fontes na janela principal, a qualquer momento." +NoSources.Label="Você não tem nenhuma fonte.\nClique no botão + abaixo, ou clique com o botão direito para adicionar uma." ChangeBG="Definir Cor" CustomColor="Cor personalizada" @@ -914,19 +938,19 @@ About.Authors="Autores" About.License="Licença" About.Contribute="Apoie o Projeto OBS" -AddUrl.Title="Adicionar Fonte via URL" -AddUrl.Text="Você arrastou um URL para o OBS. Isso irá adicionar automaticamente o link como fonte. Deseja continuar?" +AddUrl.Title="Adicionar fonte via URL" +AddUrl.Text="Você arrastou uma URL para o OBS. Isso irá adicionar automaticamente o link como fonte. Deseja continuar?" AddUrl.Text.Url="URL: %1" ResizeOutputSizeOfSource="Redimensionar saída (tamanho da fonte)" ResizeOutputSizeOfSource.Text="As resoluções base e de saída serão redimensionadas para o tamanho da fonte atual." ResizeOutputSizeOfSource.Continue="Você quer continuar?" -PreviewTransition="Prévia da Transição" +PreviewTransition="Pré-visualizar transição" -Importer="Importador de Coleção de Cenas" -Importer.SelectCollection="Selecione uma Coleção de Cenas" -Importer.Collection="Coleção de Cenas" +Importer="Importador de coleção de cenas" +Importer.SelectCollection="Selecione uma coleção de cenas" +Importer.Collection="Coleção de cenas" Importer.HelpText="Adicione arquivos a esta janela para importar coleções do OBS ou outros programas suportados." Importer.Path="Caminho da Coleção" Importer.Program="Aplicação Detectada" @@ -938,7 +962,7 @@ Restart="Reiniciar" NeedsRestart="OBS Studio precisa ser reiniciado. Deseja reiniciá-lo agora?" ContextBar.NoSelectedSource="Nenhuma fonte selecionada" -ContextBar.ResetTransform="Redefinir Transformação" +ContextBar.ResetTransform="Limpar transformação" ContextBar.FitToCanvas="Ajustar à tela" ContextBar.MediaControls.PlayMedia="Reproduzir Mídia" diff --git a/UI/data/locale/pt-PT.ini b/UI/data/locale/pt-PT.ini index 9c924a1..6c5df16 100644 --- a/UI/data/locale/pt-PT.ini +++ b/UI/data/locale/pt-PT.ini @@ -90,8 +90,10 @@ Percent="Por cento" RefreshBrowser="Atualizar" AspectRatio="Proporção %1:%2" LockVolume="Bloquear Volume" +LogViewer="Visualizador de Log" ShowOnStartup="Mostrar no arranque" OpenFile="Abrir ficheiro" +AddValue="Adicionar %1" AlreadyRunning.Title="O OBS já está em execução" AlreadyRunning.Text="O OBS já está em execução! Tem de desligar a instância existente do OBS antes de iniciar uma nova. Se o OBS estiver definido para correr na bandeja do sistema, por favor verifique se está aberto lá." @@ -159,6 +161,7 @@ Basic.AutoConfig.StreamPage.DisconnectAccount="Desconectar Conta" Basic.AutoConfig.StreamPage.DisconnectAccount.Confirm.Title="Desconectar Conta?" Basic.AutoConfig.StreamPage.DisconnectAccount.Confirm.Text="Esta alteração será aplicada imediatamente. De certeza que queres desconectar a tua conta?" Basic.AutoConfig.StreamPage.GetStreamKey="Obter chave de stream" +Basic.AutoConfig.StreamPage.MoreInfo="Mais informações" Basic.AutoConfig.StreamPage.UseStreamKey="Usar Chave de Stream" Basic.AutoConfig.StreamPage.Service="Serviço" Basic.AutoConfig.StreamPage.Service.ShowAll="Mostrar Tudo..." @@ -363,8 +366,8 @@ Deinterlacing.Yadif2x="Yadif 2x" Deinterlacing.TopFieldFirst="Campo Superior Primeiro" Deinterlacing.BottomFieldFirst="Campo Inferior Primeiro" -VolControl.SliderUnmuted="Barra de volume para '%1': %2" -VolControl.SliderMuted="Barra de volume para '%1': %2 (atualmente silenciado)" +VolControl.SliderUnmuted="Barra de volume para '%1':" +VolControl.SliderMuted="Barra de volume para '%1': (atualmente silenciado)" VolControl.Mute="Silêncio '%1'" VolControl.Properties="Propriedades de '%1'" @@ -380,6 +383,7 @@ Basic.Main.RenameSceneCollection.Title="Renomear a coleção de cena" AddProfile.Title="Adicionar perfil" AddProfile.Text="Por favor, introduza o nome do perfil" +AddProfile.WizardCheckbox="Mostrar assistente de configuração automática" RenameProfile.Title="Renomear perfil" @@ -394,6 +398,11 @@ Basic.SourceSelect.CreateNew="Criar Novo" Basic.SourceSelect.AddExisting="Adicionar Existente" Basic.SourceSelect.AddVisible="Tornar a fonte visível" +Basic.Main.Sources.Visibility="Visibilidade" +Basic.Main.Sources.VisibilityDescription="Controla a visibilidade de '%1' no ecrã" +Basic.Main.Sources.Lock="Bloquear" +Basic.Main.Sources.LockDescription="Bloqueia a posição e a escala de '%1' no ecrã" + Basic.PropertiesWindow="Propriedades para '%1'" Basic.PropertiesWindow.AutoSelectFormat="%1 (seleção automática: %2)" Basic.PropertiesWindow.SelectColor="Selecione a cor" @@ -480,6 +489,7 @@ Basic.Main.StoppingReplayBuffer="A Parar Replay Buffer..." Basic.Main.StopStreaming="Parar transmissão" Basic.Main.StoppingStreaming="A parar transmissão..." Basic.Main.ForceStopStreaming="Parar transmissão (ignorar atraso)" +Basic.Main.ShowContextBar="Mostrar Barra de Ferramentas" Basic.Main.HideContextBar="Ocultar Barra de Ferramentas" Basic.Main.StopVirtualCam="Parar Câmara Virtual" Basic.Main.Group="Grupo %1" @@ -537,7 +547,10 @@ Basic.MainMenu.View.Docks="Âncoras" Basic.MainMenu.View.Docks.ResetUI="Reiniciar Interface" Basic.MainMenu.View.Docks.LockUI="Bloquear Interface" Basic.MainMenu.View.Docks.CustomBrowserDocks="Docas de Browser Personalizadas..." +Basic.MainMenu.View.ListboxToolbars="Botões da lista de cena/origem" +Basic.MainMenu.View.ContextBar="Barra de ferramenta das fontes" Basic.MainMenu.View.SceneTransitions="Transições de &cenas" +Basic.MainMenu.View.SourceIcons="Ícones em fontes (&I)" Basic.MainMenu.View.StatusBar="Barra de e&stado" Basic.MainMenu.View.Fullscreen.Interface="Interface de ecrã inteiro" @@ -629,13 +642,19 @@ Basic.Settings.Stream.StreamSettingsWarning="Abrir definições" Basic.Settings.Stream.MissingUrlAndApiKey="O URL e a Chave de Stream estão em falta.\n\nAbra as definições e insira a chave e a URL do Stream no separador 'stream'." Basic.Settings.Stream.MissingUrl="URL do stream está em falta.\n\nVá às definições para inserir a URL no separador 'Stream'." Basic.Settings.Stream.MissingStreamKey="A chave do stream está em falta.\n\nVá às definições para inserir a chave no separador 'Stream'." +Basic.Settings.Stream.IgnoreRecommended="Ignorar recomendações de configuração do serviço de streaming" +Basic.Settings.Stream.IgnoreRecommended.Warn.Title="Substituir Configurações Recomendadas" +Basic.Settings.Stream.IgnoreRecommended.Warn.Text="Aviso: Ignorar as limitações do serviço pode resultar na redução de qualidade da transmissão ou impedir sua transmissão.\n\nContinuar?" +Basic.Settings.Stream.Recommended.MaxVideoBitrate="Bitrate máximo de vídeo: %1 kbps" +Basic.Settings.Stream.Recommended.MaxAudioBitrate="Bitrate máximo de áudio: %1 kbps" +Basic.Settings.Stream.Recommended.MaxResolution="Resolução máxima: %1" +Basic.Settings.Stream.Recommended.MaxFPS="Máximo FPS:%1" Basic.Settings.Output="Saída" Basic.Settings.Output.Format="Formato de gravação" Basic.Settings.Output.Encoder="Codificador" Basic.Settings.Output.SelectDirectory="Selecione o diretório de gravação" Basic.Settings.Output.SelectFile="Selecione ficheiro de gravação" -Basic.Settings.Output.EnforceBitrate="Forçar limites de taxa de bits de serviço de transmissão" Basic.Settings.Output.DynamicBitrate="Alterar dinamicamente a taxa de bits para gerir congestionamento" Basic.Settings.Output.DynamicBitrate.Beta="Alterar dinamicamente a taxa de bits para gerir congestionamento (beta)" Basic.Settings.Output.DynamicBitrate.TT="Em vez de perder frames para reduzir o congestionamento, muda dinamicamente a taxa de bits.\n\nNote que isto pode aumentar o atraso para os espectadores, se houver um congestionamento súbito significativo.\nQuando a taxa de bits cai, pode levar alguns minutos a ser restaurar.\n\nAtualmente só é suportado em RTMP." @@ -656,8 +675,8 @@ Basic.Settings.Output.Simple.RecordingQuality.Stream="A mesma da transmissão" Basic.Settings.Output.Simple.RecordingQuality.Small="Alta qualidade, Tamanho médio" Basic.Settings.Output.Simple.RecordingQuality.HQ="Qualidade indistinguível, Tamanho de Arquivo Grande" Basic.Settings.Output.Simple.RecordingQuality.Lossless="Sem perda de qualidade, Tamanho de Arquivo Enorme" -Basic.Settings.Output.Simple.Warn.VideoBitrate="Aviso: O bitrate do vídeo de transmissão será definido para %1, que é o limite superior para o dispositivo atual de transmissão. Se tens a certeza de que queres ir acima de %1, ativa opções de codificação avançadas e desmarca a opçáo \"Impor limites de bitrate do serviço de transmissao\"." -Basic.Settings.Output.Simple.Warn.AudioBitrate="Aviso: O bitrate do áudio de transmissão será definido para %1, que é o limite superior para o dispositivo atual de transmissão. Se tens a certeza de que queres ir acima de %1, ativa opções de codificação avançadas e desmarca a opçáo \"Impor limites de bitrate do serviço de transmissao\"." +Basic.Settings.Output.Simple.Warn.VideoBitrate="Aviso: O bitrate de vídeo da transmissão será definido para %1, que é o limite superior para o serviço de transmissão atual." +Basic.Settings.Output.Simple.Warn.AudioBitrate="Aviso: O bitrate de áudio da transmissão será definido para %1, que é o limite superior para o serviço de transmissão atual." Basic.Settings.Output.Simple.Warn.CannotPause="Aviso: As gravações não podem ser pausadas se a qualidade de gravação estiver definida como \"Mesmo que o stream\"." Basic.Settings.Output.Simple.Warn.Encoder="Aviso: Gravar com um codificador de software com uma qualidade diferente da transmissão vai exigir mais da CPU se transmitires e gravares ao mesmo tempo." Basic.Settings.Output.Simple.Warn.Lossless="Aviso: Qualidade sem perdas cria ficheiros com tamanhos tremendos! A qualidade sem perdas pode usar até 7 gigabytes de espaço no disco por minuto a altas resoluções e framerates. Não é recomendado usar qualidade sem perdas para gravações longas a não ser que tenhas muito espaço disponível no disco." @@ -668,6 +687,11 @@ 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 baixa utilização da CPU pré-ajustada, aumenta o tamanho do arquivo)" +Basic.Settings.Output.Simple.TwitchVodTrack="Trilho de VOD da Twitch (Faixa de Uso 2)" +Basic.Settings.Output.Warn.EnforceResolutionFPS.Title="Resolução/Framerate Incompatível" +Basic.Settings.Output.Warn.EnforceResolutionFPS.Msg="Este serviço de transmissão não suporta a atual resolução de saída e/ou taxa de framerate. Eles serão alterados para o valor compatível mais próximo:\n\n%1\n\n Deseja continuar?" +Basic.Settings.Output.Warn.EnforceResolutionFPS.Resolution="Resolução: %1" +Basic.Settings.Output.Warn.EnforceResolutionFPS.FPS="FPS: %1" Basic.Settings.Output.VideoBitrate="Bitrate de Vídeo" Basic.Settings.Output.AudioBitrate="Bitrate de Áudio" Basic.Settings.Output.Reconnect="Religar Automaticamente" @@ -682,7 +706,6 @@ Basic.Settings.Output.NoSpaceFileName="Gerar o Nome do Arquivo sem espaço" Basic.Settings.Output.Adv.Rescale="Redimensionar saída" Basic.Settings.Output.Adv.AudioTrack="Faixa de áudio" Basic.Settings.Output.Adv.Streaming="Transmissão" -Basic.Settings.Output.Adv.ApplyServiceSettings="Impor definições de codificação no serviço de transmissão" Basic.Settings.Output.Adv.Audio.Track1="Faixa 1" Basic.Settings.Output.Adv.Audio.Track2="Faixa 2" Basic.Settings.Output.Adv.Audio.Track3="Faixa 3" @@ -691,6 +714,7 @@ Basic.Settings.Output.Adv.Audio.Track5="Faixa 5" Basic.Settings.Output.Adv.Audio.Track6="Faixa 6" Basic.Settings.Output.Adv.Recording="Gravação" +Basic.Settings.Output.Adv.Recording.RecType="Tipo de gravação" Basic.Settings.Output.Adv.Recording.Type="Tipo" Basic.Settings.Output.Adv.Recording.Type.Standard="Padrão" Basic.Settings.Output.Adv.Recording.Type.FFmpegOutput="Saída personalizada (FFmpeg)" @@ -719,9 +743,16 @@ Basic.Settings.Output.Adv.FFmpeg.MuxerSettings="Configurações Muxer (se houver Basic.Settings.Output.Adv.FFmpeg.GOPSize="Intervalo de Keyframes (frames)" Basic.Settings.Output.Adv.FFmpeg.IgnoreCodecCompat="Mostrar todos os codecs (mesmo que potencialmente incompatíveis)" +Screenshot="Saída da Captura de Tela" +Screenshot.SourceHotkey="Capturar fonte selecionada" +Screenshot.StudioProgram="Capturar tela (programa)" +Screenshot.Preview="Capturar tela (prévia)" +Screenshot.Scene="Capturar tela (cena)" +Screenshot.Source="Capturar tela (fonte)" 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\n%FPS\n%CRES\n%ORES\n%VF" +FilenameFormatting.TT="%CCYY Ano, quatro dígitos\n%YY Ano, últimos dois dígitos (00-99)\n%MM Mês como um número decimal (01-12)\n%DD Dia do mês, começando com 0 (01-31)\n%hh Hora, em formato de 24h (00-23)\n%mm Minuto (00-59)\n%ss Segundo (00-61)\n%% A % sign\n%a Dia da Semana abreviado\n%A Nome da Semana completo\n%b Nome do Mês abreviado\n%B Nome do Mês completo\n%d Dia do Mês, começando com 0 (01-31)\n%H Hora, no formato de 24h (00-23)\n%I Hora no formato de 12h (01-12)\n%m Mês como um número decimal (01-12)\n%M Minuto (00-59)\n%p Designação AM ou PM\n%S Segundo (00-61)\n%y Ano, últimos dois dígitos (00-99)\n%Y Ano\n%z diferença do UTC em fuso horários ISO 8601 \n%Z Nome do Fuso Horário ou abreviação\n%FPS Quadros por segundo\n%CRES Resolução de base (tela)\n%ORES Resolução de saída (escala)\n%VF Formato de Vídeo" Basic.Settings.Video="Vídeo" Basic.Settings.Video.Adapter="Adaptador de Vídeo" @@ -811,13 +842,17 @@ Basic.AdvAudio="Propriedades avançadas de áudio" Basic.AdvAudio.ActiveOnly="Apenas Fontes Ativas" Basic.AdvAudio.Name="Nome" Basic.AdvAudio.Volume="Volume" +Basic.AdvAudio.VolumeSource="Volume para '%1'" Basic.AdvAudio.Mono="Mono" Basic.AdvAudio.Balance="Equilíbrio" +Basic.AdvAudio.BalanceSource="Saldo para '%1'" Basic.AdvAudio.SyncOffset="Atraso na Sincronização" +Basic.AdvAudio.SyncOffsetSource="Sincronização de deslocamento para '%1'" Basic.AdvAudio.Monitoring="Monitorização de Áudio" Basic.AdvAudio.Monitoring.None="Monitor Desligado" Basic.AdvAudio.Monitoring.MonitorOnly="Único Monitor (saída muda)" Basic.AdvAudio.Monitoring.Both="Monitor e Saída" +Basic.AdvAudio.MonitoringSource="Monitoramento de Áudio para '%1'" Basic.AdvAudio.AudioTracks="Faixas" Basic.Settings.Hotkeys="Teclas de atalho" @@ -924,5 +959,16 @@ Importer.AutomaticCollectionText="O OBS pode encontrar automaticamente coleçõe Restart="Reiniciar" NeedsRestart="OBS Studio precisa ser reiniciado. Deseja reiniciar agora?" +ContextBar.NoSelectedSource="Nenhuma fonte selecionada" +ContextBar.ResetTransform="Limpar transformação" +ContextBar.FitToCanvas="Ajustar à tela" +ContextBar.MediaControls.PlayMedia="Executar mídia" +ContextBar.MediaControls.PauseMedia="Pausar mídia" +ContextBar.MediaControls.StopMedia="Parar Mídia" +ContextBar.MediaControls.RestartMedia="Reiniciar Mídia" +ContextBar.MediaControls.PlaylistNext="Próxima na lista de reprodução" +ContextBar.MediaControls.PlaylistPrevious="Anterior na lista de reprodução" +ContextBar.MediaControls.MediaProperties="Propriedades da Mídia" +ContextBar.MediaControls.BlindSeek="Ferramenta de Procura de Mídia" diff --git a/UI/data/locale/ro-RO.ini b/UI/data/locale/ro-RO.ini index ddd24fd..205548e 100644 --- a/UI/data/locale/ro-RO.ini +++ b/UI/data/locale/ro-RO.ini @@ -93,6 +93,7 @@ LockVolume="Blochează volumul" LogViewer="Vizualizator de jurnale" ShowOnStartup="Afișează la pornire" OpenFile="Deschide fișierul" +AddValue="Adaugă %1" AlreadyRunning.Title="OBS rulează deja" AlreadyRunning.Text="OBS rulează deja! Dacă nu intenționezi să faci acest lucru, te rugăm să închizi toate instanțele OBS existente înainte de a încerca să rulezi o nouă instanță. Dacă ai OBS-ul setat să se minimizeze în bara de sistem, te rugam să verifici dacă rulează acolo." @@ -105,8 +106,8 @@ DockCloseWarning.Title="Închiderea ferestrei andocabile" DockCloseWarning.Text="Tocmai ai închis o fereastră andocabilă. Dacă dorești să o afișezi din nou, folosește meniul Vizualizare → Andocări din bara de meniu." ExtraBrowsers="Andocări personalizate pentru browser" -ExtraBrowsers.Info="Adaugă andocări dându-le o denumire și un URL, apoi dă clic pe Aplică sau Închide pentru a deschide andocările. Poți adăuga sau elimina andocări oricând." -ExtraBrowsers.DockName="Denumirea andocării" +ExtraBrowsers.Info="Adaugă andocări dându-le un nume și un URL, apoi dă clic pe Aplică sau Închide pentru a deschide andocările. Poți adăuga sau elimina andocări oricând." +ExtraBrowsers.DockName="Numele andocării" Auth.Authing.Title="Se autentifică..." Auth.Authing.Text="Se autentifică cu %1, te rugăm să aștepți..." @@ -121,10 +122,10 @@ Auth.ChannelFailure.Text="Încărcarea informațiilor canalului pentru %1 a eșu Auth.Chat="Chat" Auth.StreamInfo="Informații privind transmisiunea" TwitchAuth.Stats="Statistici Twitch" -TwitchAuth.Feed="Fluxul activității Twitch" +TwitchAuth.Feed="Flux de activitate Twitch" TwitchAuth.TwoFactorFail.Title="Nu se poate interoga cheia de transmisiune" TwitchAuth.TwoFactorFail.Text="OBS nu a putut să se conecteze la contul tău Twitch. Te rugăm să te asiguri că autentificarea cu doi factori este configurată în setările de securitate din Twitch, deoarece acest lucru este necesar pentru a transmite." -RestreamAuth.Channels="Restream canalele" +RestreamAuth.Channels="Canale Restream" Copy.Filters="Copiază filtrele" Paste.Filters="Lipește filtrele" @@ -152,7 +153,7 @@ Basic.AutoConfig.VideoPage.BaseResolution.Display="Display-ul %1 (%2x%3)" Basic.AutoConfig.VideoPage.FPS.UseCurrent="Folosește valoarea actuală (%1)" Basic.AutoConfig.VideoPage.FPS.PreferHighFPS="Fie 60 sau 30, însă prefer 60 când este posibil" Basic.AutoConfig.VideoPage.FPS.PreferHighRes="Fie 60 sau 30, însă prefer rezoluție înaltă" -Basic.AutoConfig.VideoPage.CanvasExplanation="Notă: Rezoluția (de bază) a planșei nu este neapărat aceeași cu rezoluția cu care vei transmite sau înregistra. Rezoluția efectivă de transmisiune/înregistrare poate fi subscalată de la rezoluția planșei pentru a reduce utilizarea de resurse sau cerințele privind rata de biți." +Basic.AutoConfig.VideoPage.CanvasExplanation="Notă: Rezoluția (de bază) a planșei nu este neapărat aceeași cu rezoluția cu care vei transmite sau înregistra. Rezoluția efectivă de transmisiune/înregistrare poate fi sub-scalată de la rezoluția planșei pentru a reduce utilizarea de resurse sau cerințele privind rata de biți." Basic.AutoConfig.StreamPage="Informații privind transmisiunea" Basic.AutoConfig.StreamPage.SubTitle="Te rugăm să introduci informațiile pentru transmisiune" Basic.AutoConfig.StreamPage.ConnectAccount="Conectează un cont (recomandat)" @@ -160,6 +161,7 @@ Basic.AutoConfig.StreamPage.DisconnectAccount="Deconectează contul" Basic.AutoConfig.StreamPage.DisconnectAccount.Confirm.Title="Deconectezi contul?" Basic.AutoConfig.StreamPage.DisconnectAccount.Confirm.Text="Această modificare se va aplica imediat. Ești sigur că vrei să deconectezi contul?" Basic.AutoConfig.StreamPage.GetStreamKey="Obține cheia de transmisiune" +Basic.AutoConfig.StreamPage.MoreInfo="Mai multe informații" Basic.AutoConfig.StreamPage.UseStreamKey="Folosește o cheie de transmisiune" Basic.AutoConfig.StreamPage.Service="Serviciu" Basic.AutoConfig.StreamPage.Service.ShowAll="Afișează toate..." @@ -204,8 +206,8 @@ Basic.Stats.Status="Stare" Basic.Stats.Status.Recording="Se înregistrează" Basic.Stats.Status.Live="LIVE" Basic.Stats.Status.Reconnecting="Se reconectează" -Basic.Stats.Status.Inactive="Inactivă" -Basic.Stats.Status.Active="Activă" +Basic.Stats.Status.Inactive="Inactiv(ă)" +Basic.Stats.Status.Active="Activ(ă)" Basic.Stats.DroppedFrames="Cadre pierdute (Rețea)" Basic.Stats.MegabytesSent="Date transmise în total" Basic.Stats.Bitrate="Rată de biți" @@ -228,12 +230,12 @@ Updater.FailedToLaunch="Lansarea actualizatorului a eșuat" Updater.GameCaptureActive.Title="Captură de joc activă" Updater.GameCaptureActive.Text="Biblioteca hook de captare a jocului este în prezent folosită. Te rugăm să închizi orice joc/program capturat (sau repornește Windows-ul) și încearcă din nou." -QuickTransitions.SwapScenes="Comută previzualizarea/scenele de output după tranziție" -QuickTransitions.SwapScenesTT="Schimba previzualizarea si scenele de output dupa tranzitionare (în cazul în care încă există outputul scenei originale). \nAceasta nu va anula nicio modificăre care au fost făcute la outputul scenei originale." +QuickTransitions.SwapScenes="Comută între previzualizare/scene de output după tranziție" +QuickTransitions.SwapScenesTT="Comută între previzualizare și scene de output după tranziție (în cazul în care încă există scena originală a outputului).\nAcest lucru nu va anula nicio modificare care a fost făcută la scena originală a outputului." QuickTransitions.DuplicateScene="Duplică scena" -QuickTransitions.DuplicateSceneTT="Atunci când editezi aceeași scenă, permite editarea transformării/vizibilității surselor fără modificarea outputului.\nPentru a edita proprietățile surselor fără a modifica outputul, activează 'Duplică scenele'.\nModificarea acestei valori va reseta outputul scenei actuale (în cazul în care încă există)." +QuickTransitions.DuplicateSceneTT="Când editezi aceeași scenă, permite editarea transformării/vizibilității surselor fără modificarea\noutputului. Pentru a edita proprietățile surselor fără a modifica outputul, activează „Duplică scenele”. \nModificarea acestei valori va reseta outputul scenei actuale (în cazul în care încă există)." QuickTransitions.EditProperties="Duplică scenele" -QuickTransitions.EditPropertiesTT="Atunci când editezi aceeași scenă, permite editarea proprietăților surselor fără modificarea outputului.\nAcest lucru poate fi folosit doar dacă este activată 'Duplică scenele'.\nAnumite surse (cum ar fi sursele de captare sau media) nu suportă acest lucru și nu pot fi editate separat.\nModificarea acestei valori va reseta outputul scenei actuale (în cazul în care încă există).\n\nAvertisment: Deoarece sursele vor fi duplicate, aceasta poate solicita resurse suplimentare de sistem sau video." +QuickTransitions.EditPropertiesTT="Când editezi aceeași scenă, permite editarea proprietăților surselor fără modificarea outputului. Acest lucru\npoate fi folosit numai dacă este activată „Duplică scenele”. Anumite surse (cum ar fi sursele de captură sau\nmedia) nu suportă acest lucru și nu pot fi editate separat. Modificarea acestei valori va reseta scena\nde output actuală (în cazul în care încă există).\n\nAvertisment: Deoarece sursele vor fi duplicate, aceasta poate solicita resurse suplimentare de sistem sau video." QuickTransitions.HotkeyName="Tranziție rapidă: %1" Basic.AddTransition="Adaugă tranziție configurabilă" @@ -286,7 +288,7 @@ Output.ConnectFail.Title="Conectarea a eșuat" Output.ConnectFail.BadPath="URL-ul conexiunii sau calea este nevalidă. Te rugăm să verifici setările pentru a confirma că acestea sunt valide." Output.ConnectFail.ConnectFailed="Conectarea la server a eșuat" Output.ConnectFail.InvalidStream="Nu a putut fi accesat canalul sau cheia de transmisiune specificată, te rugăm să verifici cheia de transmisiune. Dacă aceasta este corectă, poate fi o problemă cu conectarea la server." -Output.ConnectFail.Error="Eroare neașteptată la încercarea de a conecta la server. Mai multe informaţii în fişierul jurnal." +Output.ConnectFail.Error="A apărut o eroare neașteptată la încercarea de conectare la server. Mai multe informații în fișierul jurnal." Output.ConnectFail.Disconnected="Deconectat de la server." Output.StreamEncodeError.Title="Eroare privind codificarea" @@ -297,7 +299,7 @@ Output.RecordFail.Unsupported="Formatul de output este fie nesuportat, fie nu su Output.RecordNoSpace.Title="Spațiu insuficient pe disc" Output.RecordNoSpace.Msg="Nu există spațiu suficient pe disc pentru a continua înregistrarea." Output.RecordError.Title="Eroare privind înregistrarea" -Output.RecordError.Msg="S-a produs o eroare nespecificată în timpul înregistrării." +Output.RecordError.Msg="A apărut o eroare nespecificată în timpul înregistrării." Output.RecordError.EncodeErrorMsg="A apărut o eroare de codificare în timpul înregistrării." Output.BadPath.Title="Calea fișierului greșită" @@ -364,12 +366,10 @@ Deinterlacing.Yadif2x="Yadif 2x" Deinterlacing.TopFieldFirst="Câmpul superior prima oară" Deinterlacing.BottomFieldFirst="Câmpul inferior prima oară" -VolControl.SliderUnmuted="Glisor de volum pentru '%1': %2" -VolControl.SliderMuted="Glisor de volum pentru '%1': %2 (în prezent muțit)" VolControl.Mute="Mut '%1'" VolControl.Properties="Proprietăți pentru „%1”" -Basic.Main.AddSceneDlg.Title="Adaugă scenă" +Basic.Main.AddSceneDlg.Title="Adaugă o scenă" Basic.Main.AddSceneDlg.Text="Te rugăm să introduci numele scenei" Basic.Main.DefaultSceneName.Text="Scena %1" @@ -381,6 +381,7 @@ Basic.Main.RenameSceneCollection.Title="Redenumește colecția de scene" AddProfile.Title="Adaugă un profil" AddProfile.Text="Te rugăm să introduci numele profilului" +AddProfile.WizardCheckbox="Afișează asistentul de configurare automată" RenameProfile.Title="Redenumește profilul" @@ -395,6 +396,7 @@ Basic.SourceSelect.CreateNew="Creează una nouă" Basic.SourceSelect.AddExisting="Adaugă una existentă" Basic.SourceSelect.AddVisible="Fă sursa vizibilă" + Basic.PropertiesWindow="Proprietăți pentru „%1”" Basic.PropertiesWindow.AutoSelectFormat="%1 (selectare automată: %2)" Basic.PropertiesWindow.SelectColor="Selectează culoarea" @@ -406,8 +408,8 @@ Basic.PropertiesWindow.AddFiles="Adaugă fișiere" Basic.PropertiesWindow.AddDir="Adaugă un director" Basic.PropertiesWindow.AddURL="Adaugă cale/URL" Basic.PropertiesWindow.AddEditableListDir="Adaugă directorul în „%1”" -Basic.PropertiesWindow.AddEditableListFiles="Adaugă fișiere la '%1'" -Basic.PropertiesWindow.AddEditableListEntry="Adaugă intrare la '%1'" +Basic.PropertiesWindow.AddEditableListFiles="Adaugă fișiere la „%1”" +Basic.PropertiesWindow.AddEditableListEntry="Adaugă intrare la „%1”" Basic.PropertiesWindow.EditEditableListEntry="Editează intrarea de la '%1'" Basic.PropertiesView.FPS.Simple="Valori FPS simple" @@ -428,7 +430,7 @@ Basic.Filters="Filtre" Basic.Filters.AsyncFilters="Filtre audio/video" Basic.Filters.AudioFilters="Filtre audio" Basic.Filters.EffectFilters="Filtre de efecte" -Basic.Filters.Title="Filtre pentru '%1'" +Basic.Filters.Title="Filtre pentru „%1”" Basic.Filters.AddFilter.Title="Numele filtrului" Basic.Filters.AddFilter.Text="Te rugăm să specifici numele filtrului" @@ -469,7 +471,7 @@ Basic.Main.Controls="Comenzi" Basic.Main.Connecting="Se conectează..." Basic.Main.StartRecording="Pornește înregistrarea" Basic.Main.StartReplayBuffer="Pornește bufferul de reluări" -Basic.Main.SaveReplay="Salvează rejucare" +Basic.Main.SaveReplay="Salvează reluarea" Basic.Main.StartStreaming="Pornește transmisiunea" Basic.Main.StartVirtualCam="Pornește camera virtuală" Basic.Main.StopRecording="Oprește înregistrarea" @@ -627,32 +629,38 @@ Basic.Settings.Stream.Custom.Username="Nume de utilizator" Basic.Settings.Stream.Custom.Password="Parolă" Basic.Settings.Stream.BandwidthTestMode="Activează modul de testare a lățimii de bandă" Basic.Settings.Stream.TTVAddon="Suplimente pentru chatul Twitch" -Basic.Settings.Stream.TTVAddon.None="Niciuna" +Basic.Settings.Stream.TTVAddon.None="Niciunul" Basic.Settings.Stream.TTVAddon.Both="BetterTTV și FrankerFaceZ" Basic.Settings.Stream.MissingSettingAlert="Lipsește configurarea pentru transmisiune" Basic.Settings.Stream.StreamSettingsWarning="Deschide Setările" -Basic.Settings.Stream.MissingUrlAndApiKey="Cheia URL și Stream lipsesc.\n\nDeschideți setările pentru a introduce cheia URL și Stream în fila 'stream'." -Basic.Settings.Stream.MissingUrl="URL-ul de stream lipsește.\n\nDeschideți setările pentru a introduce URL-ul în tab-ul 'Stream'." -Basic.Settings.Stream.MissingStreamKey="Cheia de stream lipsește.\n\nDeschideți setările pentru a introduce cheia de transmisiune în fila 'Stream'." +Basic.Settings.Stream.MissingUrlAndApiKey="URL-ul și cheia de transmisiune lipsesc.\n\nDeschide setările pentru a introduce URL-ul și cheia de transmisiune în fila Transmisiune." +Basic.Settings.Stream.MissingUrl="URL-ul de transmisiune lipsește.\n\nDeschide setările pentru a introduce URL-ul în fila Transmisiune." +Basic.Settings.Stream.MissingStreamKey="Cheia de transmisiune lipsește.\n\nDeschide setările pentru a introduce cheia de transmisiune în fila Transmisiune." +Basic.Settings.Stream.IgnoreRecommended="Ignoră recomandările pentru setările serviciilor de transmisiune" +Basic.Settings.Stream.IgnoreRecommended.Warn.Title="Suprascrie setările recomandate" +Basic.Settings.Stream.IgnoreRecommended.Warn.Text="Avertisment: Ignorarea limitărilor serviciului poate duce la o calitate degradată a transmisiunii sau te poate împiedica să faci transmisiuni.\n\nContinui?" +Basic.Settings.Stream.Recommended.MaxVideoBitrate="Rată de biți video maximă: %1 kbps" +Basic.Settings.Stream.Recommended.MaxAudioBitrate="Rată de biți audio maximă: %1 kbps" +Basic.Settings.Stream.Recommended.MaxResolution="Rezoluție maximă: %1" +Basic.Settings.Stream.Recommended.MaxFPS="FPS maxim: %1" Basic.Settings.Output="Output" Basic.Settings.Output.Format="Format de înregistrare" Basic.Settings.Output.Encoder="Codificator" Basic.Settings.Output.SelectDirectory="Selectează directorul de înregistrări" Basic.Settings.Output.SelectFile="Selectează fișierul înregistrării" -Basic.Settings.Output.EnforceBitrate="Impune limitele ratei de biți pentru serviciul de transmisiune" Basic.Settings.Output.DynamicBitrate="Schimbă dinamic rata de biți pentru a gestiona congestionarea" Basic.Settings.Output.DynamicBitrate.Beta="Schimbă dinamic rata de biți pentru a gestiona congestionarea (Beta)" -Basic.Settings.Output.DynamicBitrate.TT="În locul pierderii de cadre pentru a reduce congestionarea, schimbă dinamic rata de biți din mers.\n\nReține că acest lucru poate crește întârzierea față de vizualizatori dacă există o congestionare bruscă semnificativă.\nCând rata de biți scade, poate dura până la câteva minute pentru a reveni la normal.\n\nÎn prezent opțiunea este suportată doar pentru RTMP." +Basic.Settings.Output.DynamicBitrate.TT="În locul pierderii de cadre pentru a reduce congestionarea, schimbă dinamic rata de biți din mers.\n\nReține că acest lucru poate crește întârzierea față de vizualizatori dacă există o congestionare bruscă\nsemnificativă. Când rata de biți scade, poate dura până la câteva minute pentru a reveni la normal.\n\nÎn prezent opțiunea este suportată doar pentru RTMP." Basic.Settings.Output.Mode="Mod de output" Basic.Settings.Output.Mode.Simple="Simplu" Basic.Settings.Output.Mode.Adv="Avansat" Basic.Settings.Output.Mode.FFmpeg="Output FFmpeg" Basic.Settings.Output.UseReplayBuffer="Activează bufferul de reluări" -Basic.Settings.Output.ReplayBuffer.SecondsMax="Timpul maxim de reluare" +Basic.Settings.Output.ReplayBuffer.SecondsMax="Timp maxim pentru reluare" Basic.Settings.Output.ReplayBuffer.MegabytesMax="Memorie maximă (megabyți)" Basic.Settings.Output.ReplayBuffer.Estimate="Utilizare estimată a memoriei: %1 MB" -Basic.Settings.Output.ReplayBuffer.EstimateUnknown="Nu se poate estima utilizarea memoriei. Vă rugăm să setați limita maximă de memorie." +Basic.Settings.Output.ReplayBuffer.EstimateUnknown="Nu se poate estima utilizarea memoriei. Te rugăm să setezi limita maximă de memorie." Basic.Settings.Output.ReplayBuffer.Prefix="Prefixul numelor fișierelor pentru bufferul de reluări" Basic.Settings.Output.ReplayBuffer.Suffix="Sufix" Basic.Settings.Output.Simple.SavePath="Cale de înregistrare" @@ -661,8 +669,8 @@ Basic.Settings.Output.Simple.RecordingQuality.Stream="La fel cu cea a transmisiu Basic.Settings.Output.Simple.RecordingQuality.Small="Calitate înaltă, dimensiune medie pentru fișiere" Basic.Settings.Output.Simple.RecordingQuality.HQ="Calitate imposibil de distins, dimensiune mare pentru fișiere" Basic.Settings.Output.Simple.RecordingQuality.Lossless="Calitate fără pierderi, dimensiune extrem de mare pentru fișiere" -Basic.Settings.Output.Simple.Warn.VideoBitrate="Avertisment: Rata de biți a transmisiei video va fi setată la %1, care este limita superioară pentru serviciul de transmisiune actual. Dacă ești sigur că vrei să depășești %1, activează opțiunile avansate ale codificatorului și debifează „Impune limitele ratei de biți pentru serviciul de transmisiune”." -Basic.Settings.Output.Simple.Warn.AudioBitrate="Avertisment: Rata de biți a transmisiei audio va fi setată la %1, care este limita superioară pentru serviciul de transmisiune actual. Dacă ești sigur că vrei să depășești %1, activează opțiunile avansate ale codificatorului și debifează „Impune limitele ratei de biți pentru serviciul de transmisiune”." +Basic.Settings.Output.Simple.Warn.VideoBitrate="Avertisment: Rata de biți pentru transmisiunea video va fi setată la %1, care este limita superioară pentru serviciul actual de transmisiune." +Basic.Settings.Output.Simple.Warn.AudioBitrate="Avertisment: Rata de biți pentru transmisiunea audio va fi setată la %1, care este limita superioară pentru serviciul actual de transmisiune." Basic.Settings.Output.Simple.Warn.CannotPause="Avertisment: Înregistrările nu pot fi puse pe pauză dacă calitatea înregistrării este setată pe „La fel cu cea a transmisiunii”." Basic.Settings.Output.Simple.Warn.Encoder="Avertisment: Înregistrarea cu un codificator software la o calitate diferită de cea a transmisiunii va necesita o utilizare CPU crescută dacă transmiți şi înregistrezi în același timp." Basic.Settings.Output.Simple.Warn.Lossless="Avertisment: Calitatea fără pierderi generează dimensiuni extrem de mari de fișiere! Calitatea fără pierderi poate folosi până la 7GB spațiu de disc per minut la frecvențe de cadre și rezoluții ridicate. Această calitate nu este recomandată pentru înregistrări lungi decât dacă ai o cantitate foarte mare de spațiu disponibil pe disc." @@ -673,6 +681,11 @@ 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 (presetare x264 cu utilizare CPU scăzută, crește dimensiunea pentru fișiere)" +Basic.Settings.Output.Simple.TwitchVodTrack="Pistă VOD Twitch (folosește pista 2)" +Basic.Settings.Output.Warn.EnforceResolutionFPS.Title="Rezoluție/Frecvența cadrelor incompatibilă" +Basic.Settings.Output.Warn.EnforceResolutionFPS.Msg="Acest serviciu de transmisiune nu suportă rezoluția actuală a outputului și/sau frecvența cadrelor. Acestea vor fi schimbate la cea mai apropiată valoare compatibilă:\n\n%1\n\nVrei să continui?" +Basic.Settings.Output.Warn.EnforceResolutionFPS.Resolution="Rezoluție: %1" +Basic.Settings.Output.Warn.EnforceResolutionFPS.FPS="FPS: %1" Basic.Settings.Output.VideoBitrate="Rată de biți video" Basic.Settings.Output.AudioBitrate="Rată de biți audio" Basic.Settings.Output.Reconnect="Reconectare automată" @@ -687,13 +700,13 @@ Basic.Settings.Output.NoSpaceFileName="Generează nume de fișiere fără spați Basic.Settings.Output.Adv.Rescale="Rescalează outputul" Basic.Settings.Output.Adv.AudioTrack="Pistă audio" Basic.Settings.Output.Adv.Streaming="Transmisiune" -Basic.Settings.Output.Adv.ApplyServiceSettings="Impune setările codificatorului pentru serviciul de transmisiune" Basic.Settings.Output.Adv.Audio.Track1="Pistă 1" Basic.Settings.Output.Adv.Audio.Track2="Pistă 2" Basic.Settings.Output.Adv.Audio.Track3="Pistă 3" Basic.Settings.Output.Adv.Audio.Track4="Pistă 4" Basic.Settings.Output.Adv.Audio.Track5="Pistă 5" Basic.Settings.Output.Adv.Audio.Track6="Pistă 6" +Basic.Settings.Output.Adv.TwitchVodTrack="Pistă VOD Twitch" Basic.Settings.Output.Adv.Recording="Înregistrare" Basic.Settings.Output.Adv.Recording.Type="Tip" @@ -738,7 +751,7 @@ Basic.Settings.Video="Video" Basic.Settings.Video.Adapter="Adaptor video" Basic.Settings.Video.BaseResolution="Rezoluție de bază (a planșei)" Basic.Settings.Video.ScaledResolution="Rezoluție a outputului (scalată)" -Basic.Settings.Video.DownscaleFilter="Filtru pentru subscalare" +Basic.Settings.Video.DownscaleFilter="Filtru pentru sub-scalare" Basic.Settings.Video.DisableAeroWindows="Dezactivează Aero (numai Windows)" Basic.Settings.Video.FPS="FPS" Basic.Settings.Video.FPSCommon="Valori FPS comune" @@ -768,7 +781,7 @@ Basic.Settings.Audio.PeakMeterType="Tipul măsurătorii vârfului" Basic.Settings.Audio.PeakMeterType.SamplePeak="Vârf eșantion" Basic.Settings.Audio.PeakMeterType.TruePeak="Vârf adevărat (Utilizare CPU mai mare)" Basic.Settings.Audio.MultiChannelWarning.Enabled="AVERTISMENT: Sunetul audio cu sunet surround este activat." -Basic.Settings.Audio.MultichannelWarning="Dacă faceți streaming, verificați dacă serviciul dvs. de streaming suportă redarea de sunet intermitentă cât și redarea de sunet intermitentă. Facebook 360 Live, Mixer RTMP, Smashcast sunt exemple în care sunetul surround este pe deplin suportat. Deşi Facebook Live şi YouTube Live acceptă ambele în surround ingest, Facebook Live downmixes la stereo, iar YouTube Live joacă doar două canale.\n\nFiltrele audio OBS sunt compatibile cu sunetul surround deși suportul pentru plugin-uri VST nu este garantat." +Basic.Settings.Audio.MultichannelWarning="Dacă faci transmisiune, verifică dacă serviciul de transmisiune suportă atât ingestia sunetului surround, cât și redarea sunetului surround. Facebook 360 Live este un exemplu în care sunetul surround este suportat pe deplin. Deși Facebook Live și YouTube Live acceptă ambele ingestia surround, Facebook Live sub-mixează în stereo, iar YouTube Live redă doar două canale.\n\nFiltrele audio OBS sunt compatibile cu sunetul surround, deși suportul pentru pluginurile VST nu este garantat." Basic.Settings.Audio.MultichannelWarning.Title="Activezi sistemul audio cu sunet surround?" Basic.Settings.Audio.MultichannelWarning.Confirm="Sigur vrei să activezi sistemul audio cu sunet surround?" Basic.Settings.Audio.Devices="Dispozitive audio globale" @@ -810,10 +823,10 @@ Basic.Settings.Advanced.Network="Rețea" Basic.Settings.Advanced.Network.BindToIP="Leagă de IP" Basic.Settings.Advanced.Network.EnableNewSocketLoop="Activează optimizările pentru rețea" Basic.Settings.Advanced.Network.EnableLowLatencyMode="Activează TCP pacing" -Basic.Settings.Advanced.Network.TCPPacing.Tooltip="Încercările de a face RTMP mai prietenos cu alte aplicații sensibile la latență din rețea, prin reglementarea ratei de transmisie.\nAcest lucru poate crește riscul de cadre abandonate la conexiunile instabile." +Basic.Settings.Advanced.Network.TCPPacing.Tooltip="Încearcă să facă RTMP mai prietenos cu alte aplicații, sensibile la latență, din rețea prin regularea ratei de transmisie.\nEste posibil să crească riscul de cadre pierdute pe conexiunile instabile." Basic.Settings.Advanced.Hotkeys.HotkeyFocusBehavior="Comportamentul focalizării pentru tastele rapide" Basic.Settings.Advanced.Hotkeys.NeverDisableHotkeys="Nu dezactiva niciodată tastele rapide" -Basic.Settings.Advanced.Hotkeys.DisableHotkeysInFocus="Dezactivează tastele rapide când fereastra principală este în prim-plan" +Basic.Settings.Advanced.Hotkeys.DisableHotkeysInFocus="Dezactivează tastele rapide când fereastra principală este focalizată" Basic.Settings.Advanced.Hotkeys.DisableHotkeysOutOfFocus="Dezactivează tastele rapide când fereastra principală nu este focalizată" Basic.Settings.Advanced.AutoRemux="Remuxează automat în mp4" Basic.Settings.Advanced.AutoRemux.MP4="(înregistrează ca mkv)" @@ -884,11 +897,11 @@ Unmute="Scoate de pe mut" Push-to-mute="Push-to-mute" Push-to-talk="Push-to-talk" -SceneItemShow="Afișează '%1'" -SceneItemHide="Ascunde '%1'" +SceneItemShow="Afișează „%1”" +SceneItemHide="Ascunde „%1”" OutputWarnings.NoTracksSelected="Trebuie să selectezi cel puțin o pistă" -OutputWarnings.MP4Recording="Avertisment: Înregistrările salvate în MP4/MOV nu vor putea fi recuperate dacă fişierul nu poate fi finalizat (de ex. ca rezultat al BSOD-urilor, pierderilor de energie etc.). Dacă doriţi să înregistraţi mai multe piese audio, luaţi în considerare utilizarea MKV şi remuxaţi înregistrarea în MP4/MOV după terminarea (Înregistrări File → Remux)" +OutputWarnings.MP4Recording="Avertisment: Înregistrările salvate în MP4/MOV nu vor putea fi recuperate dacă fişierul nu poate fi finalizat (de ex. ca urmare a BSOD-urilor, întreruperilor de alimentare etc.). Dacă vrei să înregistrezi mai multe piste audio, ia în considerare folosirea MKV şi remuxează înregistrarea în MP4/MOV după terminare (Fișier → Remuxează înregistrări)" OutputWarnings.CannotPause="Avertisment: Înregistrările nu pot fi puse pe pauză dacă codificatorul de înregistrare este setat pe „(Folosește codificatorul de transmisiune)”" FinalScene.Title="Șterge scena" @@ -896,7 +909,7 @@ FinalScene.Text="Trebuie să existe cel puțin o scenă." NoSources.Title="Nicio sursă" NoSources.Text="Se pare că nu ai adăugat încă nicio sursă video, așa că se va afișa doar un ecran negru. Sigur vrei să faci asta?" -NoSources.Text.AddSource="Puteți adăuga surse făcând clic pe pictograma + din caseta Surse în fereastra principală în orice moment." +NoSources.Text.AddSource="Poți adăuga surse dând clic pe pictograma + din caseta Surse în fereastra principală, în orice moment." NoSources.Label="Nu ai nicio sursă. Dă clic pe\nbutonul + de mai jos sau\nclic dreapta aici pentru a adăuga una." ChangeBG="Setează culoarea" diff --git a/UI/data/locale/ru-RU.ini b/UI/data/locale/ru-RU.ini index e11090c..3f3320e 100644 --- a/UI/data/locale/ru-RU.ini +++ b/UI/data/locale/ru-RU.ini @@ -93,6 +93,7 @@ LockVolume="Зафиксировать громкость" LogViewer="Просмотр журнала" ShowOnStartup="Показывать при запуске" OpenFile="Открыть файл" +AddValue="Добавить: %1" AlreadyRunning.Title="OBS уже запущен" AlreadyRunning.Text="OBS уже запущен! Пожалуйста, закройте все запущенные экземпляры OBS перед попыткой запустить новые (только если вы не хотели именно этого). Если вы настроили OBS на сворачивание в системный трей, пожалуйста, проверьте, возможно он до сих пор запущен." @@ -160,6 +161,7 @@ Basic.AutoConfig.StreamPage.DisconnectAccount="Выйти из аккаунта" Basic.AutoConfig.StreamPage.DisconnectAccount.Confirm.Title="Выход из аккаунта" Basic.AutoConfig.StreamPage.DisconnectAccount.Confirm.Text="Это изменение вступит в силу немедленно. Вы уверены, что хотите выйти?" Basic.AutoConfig.StreamPage.GetStreamKey="Получить ключ потока" +Basic.AutoConfig.StreamPage.MoreInfo="Подробная информация" Basic.AutoConfig.StreamPage.UseStreamKey="Использовать ключ потока" Basic.AutoConfig.StreamPage.Service="Сервис" Basic.AutoConfig.StreamPage.Service.ShowAll="Показать все..." @@ -364,8 +366,8 @@ Deinterlacing.Yadif2x="Yadif 2x" Deinterlacing.TopFieldFirst="Верхнее поле первое" Deinterlacing.BottomFieldFirst="Нижнее поле первое" -VolControl.SliderUnmuted="Регулятор громкости '%1': %2" -VolControl.SliderMuted="Регулятор громкости '%1': %2 (сейчас заглушен)" +VolControl.SliderUnmuted="Регулятор громкости '%1':" +VolControl.SliderMuted="Регулятор громкости '%1': (сейчас заглушен)" VolControl.Mute="Заглушить '%1'" VolControl.Properties="Свойства '%1'" @@ -381,6 +383,7 @@ Basic.Main.RenameSceneCollection.Title="Переименовать коллек AddProfile.Title="Добавить профиль" AddProfile.Text="Пожалуйста, введите имя профиля" +AddProfile.WizardCheckbox="Показать мастера автонастройки" RenameProfile.Title="Переименовать профиль" @@ -395,6 +398,11 @@ Basic.SourceSelect.CreateNew="Создать новый" Basic.SourceSelect.AddExisting="Добавить существующий" Basic.SourceSelect.AddVisible="Сделать источник видимым" +Basic.Main.Sources.Visibility="Видимость" +Basic.Main.Sources.VisibilityDescription="Управление видимостью '%1' на холсте" +Basic.Main.Sources.Lock="Заблокировать" +Basic.Main.Sources.LockDescription="Блокирует позицию и масштаб '%1' на холсте" + Basic.PropertiesWindow="Свойства '%1'" Basic.PropertiesWindow.AutoSelectFormat="%1 (автовыбор: %2)" Basic.PropertiesWindow.SelectColor="Выбрать цвет" @@ -634,13 +642,19 @@ Basic.Settings.Stream.StreamSettingsWarning="Открыть настройки" Basic.Settings.Stream.MissingUrlAndApiKey="URL и ключ потока отсутствуют.\n\nОткройте настройки, чтобы ввести URL-адрес и ключ потока на вкладке «Вещание»." Basic.Settings.Stream.MissingUrl="Отсутствует URL потока.\n\nОткройте настройки, чтобы ввести URL на вкладке «Вещание»." Basic.Settings.Stream.MissingStreamKey="Ключ потока отсутствует.\n\nОткройте настройки, чтобы ввести ключ потока на вкладке «Вещание»." +Basic.Settings.Stream.IgnoreRecommended="Игнорировать рекомендации по настройкам потокового сервиса" +Basic.Settings.Stream.IgnoreRecommended.Warn.Title="Переопределить рекомендуемые настройки" +Basic.Settings.Stream.IgnoreRecommended.Warn.Text="Предупреждение. Игнорирование ограничений службы может привести к ухудшению качества потока или помешать вам начать потоковую передачу.\n\nПродолжать?" +Basic.Settings.Stream.Recommended.MaxVideoBitrate="Максимальный битрейт видео: %1 kbps" +Basic.Settings.Stream.Recommended.MaxAudioBitrate="Максимальный битрейт аудио: %1 kbps" +Basic.Settings.Stream.Recommended.MaxResolution="Максимальное разрешение: %1" +Basic.Settings.Stream.Recommended.MaxFPS="Максимальный FPS: %1" 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.DynamicBitrate="Динамически изменять битрейт для управления перегрузкой сети" Basic.Settings.Output.DynamicBitrate.Beta="Динамически изменять битрейт для управления перегрузкой сети (бета)" Basic.Settings.Output.DynamicBitrate.TT="Вместо пропуска кадров, будет задействовано динамическое изменение битрейта на лету, чтобы уменьшить перегрузку сети.\n\nОбратите внимание, что это может увеличить задержку для зрителей, в случае внезапного забивания канала.\nПосле уменьшения битрейта может потребоваться несколько минут для его восстановления.\n\nВ настоящее время поддерживается только для RTMP." @@ -661,8 +675,8 @@ 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.VideoBitrate="Предупреждение: битрейт потокового видео будет установлен на %1, что является верхним пределом для текущей потоковой службы." +Basic.Settings.Output.Simple.Warn.AudioBitrate="Предупреждение: битрейт потокового аудио будет установлен на %1, что является верхним пределом для текущей потоковой службы." Basic.Settings.Output.Simple.Warn.CannotPause="Предупреждение: Записи не могут быть приостановлены, если кодировщик записи установлен на \"(Использовать кодировщик потока)\"." Basic.Settings.Output.Simple.Warn.Encoder="Предупреждение: Запись с программным кодировщиком в качестве, отличным от качества трансляции, потребует дополнительной нагрузки на ЦП, если записывать и транслировать одновременно." Basic.Settings.Output.Simple.Warn.Lossless="Предупреждение: Качество без потерь создаёт чрезвычайно большие файлы! Такое качество может использовать свыше 7 гигабайт дискового пространства в минуту при высоком разрешении и частоте кадров. Оно не рекомендуется для долгой записи, если у Вас нет очень много места на диске." @@ -673,6 +687,11 @@ 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.Simple.TwitchVodTrack="Twitch VOD Трек (использует трек 2)" +Basic.Settings.Output.Warn.EnforceResolutionFPS.Title="Несовместимое Разрешение/Частота кадров" +Basic.Settings.Output.Warn.EnforceResolutionFPS.Msg="Эта потоковая служба не поддерживает ваше текущее выходное разрешение и / или частоту кадров. Они будут изменены на наиболее близкое совместимое значение:\n\n%1\n\nВы хотите продолжить?" +Basic.Settings.Output.Warn.EnforceResolutionFPS.Resolution="Разрешение: %1" +Basic.Settings.Output.Warn.EnforceResolutionFPS.FPS="FPS: %1" Basic.Settings.Output.VideoBitrate="Битрейт видео" Basic.Settings.Output.AudioBitrate="Битрейт аудио" Basic.Settings.Output.Reconnect="Автоматическое переподключение" @@ -687,15 +706,16 @@ 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.Audio.Track5="Дорожка 5" Basic.Settings.Output.Adv.Audio.Track6="Дорожка 6" +Basic.Settings.Output.Adv.TwitchVodTrack="Twitch VOD Track" Basic.Settings.Output.Adv.Recording="Запись" +Basic.Settings.Output.Adv.Recording.RecType="Тип записи" Basic.Settings.Output.Adv.Recording.Type="Тип" Basic.Settings.Output.Adv.Recording.Type.Standard="Обычный" Basic.Settings.Output.Adv.Recording.Type.FFmpegOutput="Пользовательский вывод (FFmpeg)" @@ -823,13 +843,18 @@ Basic.AdvAudio="Расширенные свойства аудио" Basic.AdvAudio.ActiveOnly="Только активные источники" Basic.AdvAudio.Name="Название" Basic.AdvAudio.Volume="Громкость" +Basic.AdvAudio.VolumeSource="Звук для '%1'" Basic.AdvAudio.Mono="Моно" +Basic.AdvAudio.MonoSource="Моно Downmix для '%1'" Basic.AdvAudio.Balance="Баланс" +Basic.AdvAudio.BalanceSource="Баланс для '%1'" Basic.AdvAudio.SyncOffset="Смещение синхронизации" +Basic.AdvAudio.SyncOffsetSource="Синхронизировать смещение для '%1'" Basic.AdvAudio.Monitoring="Прослушивание аудио" Basic.AdvAudio.Monitoring.None="Выключить прослушивание" Basic.AdvAudio.Monitoring.MonitorOnly="Только прослушивание (заглушить вывод)" Basic.AdvAudio.Monitoring.Both="Прослушивание и вывод" +Basic.AdvAudio.MonitoringSource="Аудиомониторинг для '%1'" Basic.AdvAudio.AudioTracks="Дорожки" Basic.Settings.Hotkeys="Горячие клавиши" diff --git a/UI/data/locale/si-LK.ini b/UI/data/locale/si-LK.ini index 7122fe7..3cca9b3 100644 --- a/UI/data/locale/si-LK.ini +++ b/UI/data/locale/si-LK.ini @@ -116,5 +116,6 @@ Seconds="තත්පර" + diff --git a/UI/data/locale/sk-SK.ini b/UI/data/locale/sk-SK.ini index 0530cd3..575eaae 100644 --- a/UI/data/locale/sk-SK.ini +++ b/UI/data/locale/sk-SK.ini @@ -1,5 +1,5 @@ -Language="Slovenčina" +Language="slovenčina" OK="OK" Apply="Použiť" @@ -161,6 +161,7 @@ Basic.AutoConfig.StreamPage.DisconnectAccount="Odpojiť účet" Basic.AutoConfig.StreamPage.DisconnectAccount.Confirm.Title="Odpojiť účet?" Basic.AutoConfig.StreamPage.DisconnectAccount.Confirm.Text="Táto zmena sa uplatní okamžite. Naozaj chcete odpojiť svoj účet?" Basic.AutoConfig.StreamPage.GetStreamKey="Dostať Streamovací Kľúč" +Basic.AutoConfig.StreamPage.MoreInfo="Viac informácií" Basic.AutoConfig.StreamPage.UseStreamKey="Použiť kľúč vysielania" Basic.AutoConfig.StreamPage.Service="Služba" Basic.AutoConfig.StreamPage.Service.ShowAll="Zobraziť všetky..." @@ -365,8 +366,8 @@ Deinterlacing.Yadif2x="Yadif 2x" Deinterlacing.TopFieldFirst="Najprv vrchný riadok" Deinterlacing.BottomFieldFirst="Najprv spodný riadok" -VolControl.SliderUnmuted="Posuvník hlasitosti pre '%1': %2" -VolControl.SliderMuted="Ovládanie hlasitosti pre '%1': %2 (momentálne umlčané)" +VolControl.SliderUnmuted="Posuvník hlasitosti pre '%1':" +VolControl.SliderMuted="Ovládanie hlasitosti pre '%1': (momentálne umlčané)" VolControl.Mute="Umlčať '%1'" VolControl.Properties="Vlastnosti pre '%1'" @@ -382,6 +383,7 @@ Basic.Main.RenameSceneCollection.Title="Premenovať sadu scén" AddProfile.Title="Pridanie profilu" AddProfile.Text="Prosím, zadajte názov profilu" +AddProfile.WizardCheckbox="Ukázať sprievodcu automatickou konfiguráciou" RenameProfile.Title="Premenovať profil" @@ -396,6 +398,11 @@ Basic.SourceSelect.CreateNew="Vytvoriť nový" Basic.SourceSelect.AddExisting="Pridať existujúci" Basic.SourceSelect.AddVisible="Zviditeľniť zdroj" +Basic.Main.Sources.Visibility="Viditeľnosť" +Basic.Main.Sources.VisibilityDescription="Ovláda viditeľnosť '%1' na plátne" +Basic.Main.Sources.Lock="Zámok" +Basic.Main.Sources.LockDescription="Uzamkne pozíciu a škálu '%1' na plátne" + Basic.PropertiesWindow="Vlastnosti pre '%1'" Basic.PropertiesWindow.AutoSelectFormat="%1 (Automatický výber: %2)" Basic.PropertiesWindow.SelectColor="Vybrať farbu" @@ -472,7 +479,7 @@ Basic.Main.StartRecording="Spustiť nahrávanie" Basic.Main.StartReplayBuffer="Spustiť záznam do pamäte" Basic.Main.SaveReplay="Uložiť záznam" Basic.Main.StartStreaming="Spustiť stream" -Basic.Main.StartVirtualCam="Spustite virtuálnu kameru" +Basic.Main.StartVirtualCam="Spustiť virtuálnu kameru" Basic.Main.StopRecording="Ukončiť nahrávanie" Basic.Main.PauseRecording="Pozastaviť nahrávanie" Basic.Main.UnpauseRecording="Pokračovať v nahrávaní" @@ -484,7 +491,7 @@ Basic.Main.StoppingStreaming="Zastavenie streamu..." Basic.Main.ForceStopStreaming="Zastaviť vysielanie (bez oneskorenia)" Basic.Main.ShowContextBar="Zobraziť panel nástrojov zdroja" Basic.Main.HideContextBar="Skryť panel nástrojov zdroja" -Basic.Main.StopVirtualCam="Vypnite virtuálnu kameru" +Basic.Main.StopVirtualCam="Vypnúť virtuálnu kameru" Basic.Main.Group="Skupina %1" Basic.Main.GroupItems="Zoskupiť vybrané položky" Basic.Main.Ungroup="Rozdeliť skupinu" @@ -635,13 +642,19 @@ Basic.Settings.Stream.StreamSettingsWarning="Otvoriť nastavenia" Basic.Settings.Stream.MissingUrlAndApiKey="Chýba vysielací kľúč a adresa.\n\nOtvorte nastavenia pre zadanie vysielacieho kľúča a adresy v záložke 'Vysielanie'." Basic.Settings.Stream.MissingUrl="Chýba vysielacia adresa.\n\nOtvorte nastavenia pre zadanie vysielacej adresy v záložke 'Vysielanie'." Basic.Settings.Stream.MissingStreamKey="Chýba vysielací kľúč.\n\nOtvorte nastavenia pre zadanie vysielacieho kľúča v záložke 'Vysielanie'." +Basic.Settings.Stream.IgnoreRecommended="Ignorovať odporučené nastavenia streamovacej služby" +Basic.Settings.Stream.IgnoreRecommended.Warn.Title="Prepísať Odporúčané Nastavenia" +Basic.Settings.Stream.IgnoreRecommended.Warn.Text="Varovanie: Ignorovanie obmedzení služby môže mať za následok zníženú kvalitu streamu alebo môže úplne zabrániť streamovaniu.\n\nPokračovať?" +Basic.Settings.Stream.Recommended.MaxVideoBitrate="Maximálny Video Bitrate: %1 kbps" +Basic.Settings.Stream.Recommended.MaxAudioBitrate="Maximálny Audio Bitrate: %1 kbps" +Basic.Settings.Stream.Recommended.MaxResolution="Maximálne rozlíšenie: %1" +Basic.Settings.Stream.Recommended.MaxFPS="Maximálne FPS: %1" Basic.Settings.Output="Výstup" Basic.Settings.Output.Format="Formát nahrávania" Basic.Settings.Output.Encoder="Enkodér" Basic.Settings.Output.SelectDirectory="Vybrať adresár pre nahrávky" Basic.Settings.Output.SelectFile="Vybrať súbor nahrávky" -Basic.Settings.Output.EnforceBitrate="Vynútiť obmedzenia bitratu streamovacej služby" Basic.Settings.Output.DynamicBitrate="Dynamicky meniť bitrate v závislosti na zahltení siete" Basic.Settings.Output.DynamicBitrate.Beta="Dynamicky meniť bitrate v závislosti na zahltení siete (Beta)" Basic.Settings.Output.DynamicBitrate.TT="Dynamicky mení bitrate počas behu, namiesto odhadzovania snímkov pre redukciu zahltenia siete.\n\nToto ale môže mať za následok zvýšenie odozvy pre divákov, keď dôjde k náhlemu zahlteniu siete.\nKeď sa bitrate zníži, môže pár minúť trvať než sa obnoví na pôvodnú hodnotu.\n\nMomentálne podporované iba pre RTMP." @@ -662,8 +675,8 @@ Basic.Settings.Output.Simple.RecordingQuality.Stream="Rovnaká ako pre vysielani Basic.Settings.Output.Simple.RecordingQuality.Small="Vysoká kvalita, stredná veľkosť súboru" Basic.Settings.Output.Simple.RecordingQuality.HQ="Nerozoznateľná kvalita, veľká veľkosť súboru" Basic.Settings.Output.Simple.RecordingQuality.Lossless="Bezstratová kvalita, ohromne veľké súbory" -Basic.Settings.Output.Simple.Warn.VideoBitrate="Upozornenie: Bitrate vysielaného obrazu bude nastavený na %1, čo je horná hranica pre súčasnú vysielaciu službu. Ak ste si istý, že chcete vysielať nad %1, v rozšírených nastaveniach enkodéra zakážte \"Vynútiť obmedzenia bitratu streamovacej služby\"." -Basic.Settings.Output.Simple.Warn.AudioBitrate="Upozornenie: Bitrate vysielaného zvuku bude nastavený na %1, čo je horná hranica pre súčasnú vysielaciu službu. Ak ste si istý, že chcete vysielať nad %1, v rozšírených nastaveniach enkodéra zakážte \"Vynútiť obmedzenia bitratu streamovacej služby\"." +Basic.Settings.Output.Simple.Warn.VideoBitrate="Varovanie: Streamovací video bitrate bude nastavený na %1, čo je horný limit pre momentálnu streamovaciu službu." +Basic.Settings.Output.Simple.Warn.AudioBitrate="Varovanie: Streamovací audio bitrate bude nastavený na %1, čo je horný limit pre momentálnu streamovaciu službu." Basic.Settings.Output.Simple.Warn.CannotPause="Upozornenie: Nahrávanie nemôže byť pozastavené, ak je kvalita nahrávania nastavená na \"Rovnaké ako pre vysielanie\"." Basic.Settings.Output.Simple.Warn.Encoder="Upozornenie: Nahrávanie softvérovým kodérom s rozdielnou kvalitou než vysielanie spôsobí zvýšenú záťaž CPU pri nahrávaní a vysielaní zároveň." Basic.Settings.Output.Simple.Warn.Lossless="Varovanie: Bezstratová kvalita generuje ohromne veľké súbory! Bezstratová kvalita môže použiť až 7 gigabajtov za minútu na disku pri vysokých rozlíšeniach a snímkoch za sekundu. Bezstratová kvalita nie je odporúčaná pre dlhé nahrávky pokiaľ nemáte veľmi veľa priestoru na disku." @@ -674,6 +687,11 @@ Basic.Settings.Output.Simple.Encoder.Hardware.QSV="Hardvérový (QSV)" Basic.Settings.Output.Simple.Encoder.Hardware.AMD="Hardvérový (AMD)" Basic.Settings.Output.Simple.Encoder.Hardware.NVENC="Hardvérový (NVENC)" Basic.Settings.Output.Simple.Encoder.SoftwareLowCPU="Softvérový (x264, nízke zaťaženie CPU, zvyšuje veľkosť súboru)" +Basic.Settings.Output.Simple.TwitchVodTrack="Twitch VOD záznam (používa stopu 2)" +Basic.Settings.Output.Warn.EnforceResolutionFPS.Title="Nekompatibilné rozlíšenie/snímková frekvencia" +Basic.Settings.Output.Warn.EnforceResolutionFPS.Msg="Táto streamovacia služba nepodporuje vaše momentálne výstupne rozlíšenie a/alebo snímkovú frekvenciu. Budú zmenené na najbližšiu kompatibilnú hodnotu:\n\n%1\n\nChcete pokračovať?" +Basic.Settings.Output.Warn.EnforceResolutionFPS.Resolution="Rozlíšenie: %1" +Basic.Settings.Output.Warn.EnforceResolutionFPS.FPS="FPS: %1" Basic.Settings.Output.VideoBitrate="Bitrate videa" Basic.Settings.Output.AudioBitrate="Bitrate zvuku" Basic.Settings.Output.Reconnect="Automatické znovupripojenie" @@ -688,15 +706,16 @@ Basic.Settings.Output.NoSpaceFileName="Vygenerovať názov súboru bez medzier" Basic.Settings.Output.Adv.Rescale="Škálovať výstup" Basic.Settings.Output.Adv.AudioTrack="Zvuková stopa" Basic.Settings.Output.Adv.Streaming="Vysielanie" -Basic.Settings.Output.Adv.ApplyServiceSettings="Vynútiť nastavenia kodéra vysielacou službou" Basic.Settings.Output.Adv.Audio.Track1="Stopa 1" Basic.Settings.Output.Adv.Audio.Track2="Stopa 2" Basic.Settings.Output.Adv.Audio.Track3="Stopa 3" Basic.Settings.Output.Adv.Audio.Track4="Stopa 4" Basic.Settings.Output.Adv.Audio.Track5="Stopa 5" Basic.Settings.Output.Adv.Audio.Track6="Stopa 6" +Basic.Settings.Output.Adv.TwitchVodTrack="Twitch VOD záznam" Basic.Settings.Output.Adv.Recording="Nahrávanie" +Basic.Settings.Output.Adv.Recording.RecType="Typ nahrávania" Basic.Settings.Output.Adv.Recording.Type="Typ" Basic.Settings.Output.Adv.Recording.Type.Standard="Štandardný" Basic.Settings.Output.Adv.Recording.Type.FFmpegOutput="Vlastný výstup (FFmpeg)" @@ -824,13 +843,18 @@ Basic.AdvAudio="Pokročilé nastavenia zvuku" Basic.AdvAudio.ActiveOnly="Iba Aktívne Zdroje" Basic.AdvAudio.Name="Názov" Basic.AdvAudio.Volume="Hlasitosť" +Basic.AdvAudio.VolumeSource="Hlasitosť pre '%1'" Basic.AdvAudio.Mono="Mono" +Basic.AdvAudio.MonoSource="Mono Downmix pre '%1'" Basic.AdvAudio.Balance="Vyváženie" +Basic.AdvAudio.BalanceSource="Vyváženie pre '%1'" Basic.AdvAudio.SyncOffset="Oneskorenie synchronizácie" +Basic.AdvAudio.SyncOffsetSource="Odchýlka synchronizácie pre '%1'" Basic.AdvAudio.Monitoring="Monitorovanie zvuku" Basic.AdvAudio.Monitoring.None="Vypnuté monitorovanie" Basic.AdvAudio.Monitoring.MonitorOnly="Iba monitorovanie (žiaden výstup)" Basic.AdvAudio.Monitoring.Both="Monitorovanie a výstup" +Basic.AdvAudio.MonitoringSource="Monitorovanie zvuku pre '%1'" Basic.AdvAudio.AudioTracks="Stopy" Basic.Settings.Hotkeys="Klávesové skratky" diff --git a/UI/data/locale/sl-SI.ini b/UI/data/locale/sl-SI.ini index 6837d7b..209603c 100644 --- a/UI/data/locale/sl-SI.ini +++ b/UI/data/locale/sl-SI.ini @@ -26,7 +26,7 @@ Mixer="Mešalnik zvoka" Browse="Brskaj" Mono="Mono" Stereo="Stereo" -DroppedFrames="Izpuščene sličice %1 (%2 %)" +DroppedFrames="Spuščeni okvirji %1 (%2 %)" StudioProgramProjector="Celozaslonski projektor (program)" PreviewProjector="Celozaslonski projektor (predogled)" SceneProjector="Celozaslonski projektor (prizor)" @@ -58,9 +58,9 @@ Right="Desno" Top="Zgoraj" Bottom="Spodaj" Reset="Ponastavi" -Hours="urah" -Minutes="minutah" -Seconds="sekundah" +Hours="ur" +Minutes="minut" +Seconds="sekund" Deprecated="Opuščeno" ReplayBuffer="Medpomn. za pon. predv." Import="Uvozi" @@ -87,13 +87,20 @@ Calculating="Računanje..." Fullscreen="Celozaslonsko" Windowed="Okensko" Percent="Odstotkov" +RefreshBrowser="Osveži" AspectRatio="Razmerje slike %1%2" LockVolume="Zakleni glasnost" +LogViewer="Pregledovalnik dnevnika" +ShowOnStartup="Pokaži ob zagonu" +OpenFile="Odpri datoteko" +AddValue="Dodaj %1" AlreadyRunning.Title="OBS se že izvaja" -AlreadyRunning.Text="OBS se že izvaja! Razen če ste imeli namen zagnati več primerkov, pred zagonom novega primerka OBS-a zaustavite vse obstoječe. Če imate OBS nastavljen, da se skrči v sistemsko vrstico, preverite, če se tam še izvaja." +AlreadyRunning.Text="OBS se že izvaja! Če tega niste že storili, zaprite vse obstoječe primerke OBS, preden poskusite zagnati nov primerek. Če imate OBS nastavljen, da se zmanjša v sistemsko vrstico, preverite, ali se tam še vedno izvaja." AlreadyRunning.LaunchAnyway="Vseeno zaženi" +ChromeOS.Title="Nepodprta platforma" +ChromeOS.Text="Izgleda, se OBS izvaja znotraj kontejnerja. Ta platforma ni podprta" DockCloseWarning.Title="Zapiranje sidrnega okna" DockCloseWarning.Text="Pravkar ste zaprli okno sidrišča. Če bi ga radi zopet prikazali, uporabite meni Pogled → Sidrišča." @@ -130,7 +137,7 @@ BandwidthTest.Region="Regija" BandwidthTest.Region.US="Združene države Amerike" BandwidthTest.Region.EU="Evropa" BandwidthTest.Region.Asia="Azija" -BandwidthTest.Region.Other="Drugo" +BandwidthTest.Region.Other="Ostalo" Basic.AutoConfig="Čarovnik za samodejno nastavitev" Basic.AutoConfig.ApplySettings="Uporabi nastavitve" @@ -140,6 +147,7 @@ Basic.AutoConfig.StartPage.PrioritizeStreaming="Optimiziraj za pretakanje - snem Basic.AutoConfig.StartPage.PrioritizeRecording="Optimiziraj samo za snemanje - ne bom pretakal" Basic.AutoConfig.StartPage.PrioritizeVirtualCam="Uporabljala se bo samo virtualna kamera" Basic.AutoConfig.VideoPage="Nastavitve videa" +Basic.AutoConfig.VideoPage.SubTitle="Določite želene nastavitve videa, ki bi jih radi uporabili" Basic.AutoConfig.VideoPage.BaseResolution.UseCurrent="Uporabi trenutno (%1x%2)" Basic.AutoConfig.VideoPage.BaseResolution.Display="Zaslon %1 (%2x%3)" Basic.AutoConfig.VideoPage.FPS.UseCurrent="Uporabi trenutno (%1)" @@ -153,6 +161,7 @@ Basic.AutoConfig.StreamPage.DisconnectAccount="Odklopi račun" Basic.AutoConfig.StreamPage.DisconnectAccount.Confirm.Title="Odklopim račun?" Basic.AutoConfig.StreamPage.DisconnectAccount.Confirm.Text="Ta sprememba bo začela veljati takoj. Ali res želite odklopiti račun?" Basic.AutoConfig.StreamPage.GetStreamKey="Dobi ključ pretoka" +Basic.AutoConfig.StreamPage.MoreInfo="Več informacij" Basic.AutoConfig.StreamPage.UseStreamKey="Uporabi ključ pretoka" Basic.AutoConfig.StreamPage.Service="Storitev" Basic.AutoConfig.StreamPage.Service.ShowAll="Prikaži vse..." @@ -180,7 +189,7 @@ Basic.AutoConfig.TestPage.TestingRes.Resolution="Preizkušanje %1x%2 %3 sl./s... Basic.AutoConfig.TestPage.Result.StreamingEncoder="Kodirnik pretoka" Basic.AutoConfig.TestPage.Result.RecordingEncoder="Snemalni kodirnik" Basic.AutoConfig.TestPage.Result.Header="Program je ocenil, da so te nastavitve najprimernejše za vas:" -Basic.AutoConfig.TestPage.Result.Footer="Za uporabo teh nastavitev kliknite 'Uporabi nastavitve'. Za ponovno nastavitev čarovnika in vnovičen poizkus kliknite 'Nazaj'. Za ročno nastavitev kliknite 'Prekliči' in odprite nastavitve." +Basic.AutoConfig.TestPage.Result.Footer="Za uporabo teh nastavitev kliknite 'Uporabi nastavitve'. Za ponovno nastavitev čarovnika in vnovičen poskus kliknite 'Nazaj'. Za ročno nastavitev kliknite 'Prekliči' in odprite nastavitve." Basic.AutoConfig.Info="Namestitveni čarovnik bo določil najboljše nastavitve glede na tehnične specifikacije računalnika in na internetno povezavo." Basic.AutoConfig.RunAnytime="To lahko kadarkoli zaženete iz menija Orodja." @@ -260,7 +269,7 @@ ConfirmStopRecord.Text="Ali res želite prenehati snemati?" ConfirmBWTest.Title="Zaženi preizkus pasovne širine?" ConfirmBWTest.Text="OBS imate nastavljen v načinu preizkusa pasovne širine. Ta način omogoča preizkušanje omrežja brez oddajanja v živo. Ko končate s preizkusom, ga boste morali onemogočiti, da si bodo gledalci lahko ogledali vaš pretok.\n\nŽelite nadaljevati?" -ConfirmExit.Title="Zapusti OBS?" +ConfirmExit.Title="Želite zapustiti OBS?" ConfirmExit.Text="OBS je trenutno aktiven. Vsi pretoki/snemanja bodo ustavljeni. Ali res želite končati?" ConfirmRemove.Title="Potrdite odstranitev" @@ -286,7 +295,7 @@ Output.StreamEncodeError.Title="Napaka pri kodiranju" Output.StreamEncodeError.Msg="Med pretakanjem se je pojavila napaka kodirnika." Output.RecordFail.Title="Zagon snemanja je spodletel" -Output.RecordFail.Unsupported="Izhodni format ni podprt ali pa ne podpira več kot ene zvočne sledi. Preverite nastavitve in poizkusite znova." +Output.RecordFail.Unsupported="Izhodni format ni podprt ali pa ne podpira več kot ene zvočne steze. Preverite nastavitve in poizkusite znova." Output.RecordNoSpace.Title="Premalo prostora na disku" Output.RecordNoSpace.Msg="Za nadaljevanje snemanja na disku ni dovolj prostora." Output.RecordError.Title="Napaka pri snemanju" @@ -357,8 +366,6 @@ Deinterlacing.Yadif2x="Yadif 2x" Deinterlacing.TopFieldFirst="Najprej zgornje polje" Deinterlacing.BottomFieldFirst="Najprej spodnje polje" -VolControl.SliderUnmuted="Drsnik glasnosti za '%1': %2" -VolControl.SliderMuted="Drsnik glasnosti za '%1': %2 (trenutno je utišano)" VolControl.Mute="Utišaj '%1'" VolControl.Properties="Lastnosti za '%1'" @@ -374,6 +381,7 @@ Basic.Main.RenameSceneCollection.Title="Preimenuj zbirko prizorov" AddProfile.Title="Dodaj profil" AddProfile.Text="Vnesite ime profila" +AddProfile.WizardCheckbox="Prikaži čarovnika za samodejno konfiguracijo" RenameProfile.Title="Preimenuj profil" @@ -388,6 +396,7 @@ Basic.SourceSelect.CreateNew="Ustvari novega" Basic.SourceSelect.AddExisting="Dodaj obstoječega" Basic.SourceSelect.AddVisible="Prikaži vir" + Basic.PropertiesWindow="Lastnosti za '%1'" Basic.PropertiesWindow.AutoSelectFormat="%1 (samodejno izberi: %2)" Basic.PropertiesWindow.SelectColor="Izberi barvo" @@ -474,6 +483,8 @@ Basic.Main.StoppingReplayBuffer="Ustavljanje medp. ponovitve..." Basic.Main.StopStreaming="Prenehaj pretakati" Basic.Main.StoppingStreaming="Ustavljanje pretoka …" Basic.Main.ForceStopStreaming="Prenehaj pretakati (zavrzi zakasnitev)" +Basic.Main.ShowContextBar="Pokaži orodno vrstico vira" +Basic.Main.HideContextBar="Skrij orodno vrstico vira" Basic.Main.StopVirtualCam="Zaustavitev virtualne kamere" Basic.Main.Group="%1. skupina" Basic.Main.GroupItems="Združi izbrane predmete" @@ -530,6 +541,8 @@ Basic.MainMenu.View.Docks="Sidrišča" Basic.MainMenu.View.Docks.ResetUI="Ponastavi up. vmesnik" Basic.MainMenu.View.Docks.LockUI="Zakleni up. vmesnik" Basic.MainMenu.View.Docks.CustomBrowserDocks="Prilagojena sidrišča brskalnika..." +Basic.MainMenu.View.ListboxToolbars="Gumbi za seznam prizorov/virov" +Basic.MainMenu.View.ContextBar="Orodna vrstica vira" Basic.MainMenu.View.SceneTransitions="P&rehodi prizorov" Basic.MainMenu.View.SourceIcons="&Ikone virov" Basic.MainMenu.View.StatusBar="Vr&stica stanja" @@ -623,13 +636,19 @@ Basic.Settings.Stream.StreamSettingsWarning="Odpri nastavitve" Basic.Settings.Stream.MissingUrlAndApiKey="Manjkata URL in ključ pretoka.\n\nOdprite nastavitve za vnos URLja in ključa pretoka v zavihek 'Pretok'." Basic.Settings.Stream.MissingUrl="Manjka URL pretoka.\n\nOdprite nastavitve za vnos URLja v zavihek 'Pretok'." Basic.Settings.Stream.MissingStreamKey="Manjka ključ pretoka.\n\nOdprite nastavitve za vnos ključa pretoka v zavihek 'Pretok'." +Basic.Settings.Stream.IgnoreRecommended="Prezri priporočila za nastavitev storitve pretakanja" +Basic.Settings.Stream.IgnoreRecommended.Warn.Title="Preglasite priporočene nastavitve" +Basic.Settings.Stream.IgnoreRecommended.Warn.Text="Opozorilo: neupoštevanje omejitev storitve lahko povzroči poslabšanje kakovosti pretočnega predvajanja ali prepreči pretakanje.\n\nNadaljujem?" +Basic.Settings.Stream.Recommended.MaxVideoBitrate="Največja bitna hitrost videa: %1 kbps" +Basic.Settings.Stream.Recommended.MaxAudioBitrate="Največja bitna hitrost zvoka: %1 kbps" +Basic.Settings.Stream.Recommended.MaxResolution="Največja ločljivost: %1" +Basic.Settings.Stream.Recommended.MaxFPS="Največje število sl./s: %1" Basic.Settings.Output="Izhod" Basic.Settings.Output.Format="Format posnetkov" Basic.Settings.Output.Encoder="Kodirnik" Basic.Settings.Output.SelectDirectory="Izberite mapo za posnetke" Basic.Settings.Output.SelectFile="Izberite datoteko posnetka" -Basic.Settings.Output.EnforceBitrate="Za pretočne storitve vsili omejitve bitne hitrost" Basic.Settings.Output.DynamicBitrate="Dinamično spreminjaj bitno hitrost za odpravo zastojev" Basic.Settings.Output.DynamicBitrate.Beta="Dinamično spreminjaj bitno hitrost za odpravo zastojev (beta)" Basic.Settings.Output.DynamicBitrate.TT="Namesto izpuščanja sličic za odpravo zastojev sproti dinamično spreminja bitno hitrost.\n\nUpoštevajte, da to lahko poveča zakasnitve pri gledalcih, če pride do nenadnega znatnega zastoja.\nKo se bitna hitrost zniža, lahko obnovitev traja nekaj minut.\n\nTrenutno podprto samo za RMTP." @@ -650,8 +669,8 @@ Basic.Settings.Output.Simple.RecordingQuality.Stream="Enaka kot za pretok" Basic.Settings.Output.Simple.RecordingQuality.Small="Visoka kakovost, srednja velikost datoteke" Basic.Settings.Output.Simple.RecordingQuality.HQ="Nerazločljiva kakovost, zelo velika velikost datoteke" Basic.Settings.Output.Simple.RecordingQuality.Lossless="Brezizgubna kakovost, izjemno velika velikost datoteke" -Basic.Settings.Output.Simple.Warn.VideoBitrate="Opozorilo: bitna hitrost video pretoka bo nastavljena na %1, kar je zgornja meja trenutne pretočne storitve. Če ste prepričani, da želite preseči %1, vklopite napredne možnosti kodirnika in odznačite \"Za pretočne storitve vsili omejitve bitne hitrosti\"." -Basic.Settings.Output.Simple.Warn.AudioBitrate="Opozorilo: bitna hitrost zvočnega pretoka bo nastavljena na %1, kar je zgornja meja trenutne pretočne storitve. Če ste prepričani, da želite preseči %1, vklopite napredne možnosti kodirnika in odznačite \"Za pretočne storitve vsili omejitve bitne hitrosti\"." +Basic.Settings.Output.Simple.Warn.VideoBitrate="Opozorilo: bitna hitrost pretočnega videa bo nastavljena na %1, kar je zgornja meja za trenutno storitev pretakanja." +Basic.Settings.Output.Simple.Warn.AudioBitrate="Opozorilo: bitna hitrost pretočnega zvoka bo nastavljena na %1, kar je zgornja meja za trenutno storitev pretakanja." Basic.Settings.Output.Simple.Warn.CannotPause="Opozorilo: posnetkov ni mogoče začasno ustaviti, če je kakovost posnetka nastavljena na \"Enaka kot pri pretakanju\"." Basic.Settings.Output.Simple.Warn.Encoder="Opozorilo: snemanje s programskim kodirnikom z drugačno kakovostjo, kot jo ima pretok zahteva dodatno obremenitev procesorja, kadar hkrati pretakate in snemate." Basic.Settings.Output.Simple.Warn.Lossless="Opozorilo: brezizgubna kakovost ustvari izjemno velike velikosti datotek! Brezizgubna kakovost lahko porabi več kot 7 GB prostora na disku na minuto pri visokih ločljivostih in hitrostih sličic. Brezizgubna kakovost ni priporočljiva za dolge posnetke, razen če imate na voljo veliko prostora na disku." @@ -662,6 +681,11 @@ Basic.Settings.Output.Simple.Encoder.Hardware.QSV="Strojni (QSV)" Basic.Settings.Output.Simple.Encoder.Hardware.AMD="Strojni (AMD)" Basic.Settings.Output.Simple.Encoder.Hardware.NVENC="Strojni (NVENC)" Basic.Settings.Output.Simple.Encoder.SoftwareLowCPU="Programski (prednastavitev x264 s nizko porabo CPE-ja, poveča velikost datoteke)" +Basic.Settings.Output.Simple.TwitchVodTrack="Twitch VOD Track (Uporablja stezo 2)" +Basic.Settings.Output.Warn.EnforceResolutionFPS.Title="Ločljivost ali št. sl./s nista podprta" +Basic.Settings.Output.Warn.EnforceResolutionFPS.Msg="Ta pretočna storitev ne podpira trenutne izhodne ločljivosti in/ali števila slik na sekundo. Spremenjena bosta na najbližjo podprto vrednost:\n\n%1\n\nAli želite nadaljevati?" +Basic.Settings.Output.Warn.EnforceResolutionFPS.Resolution="Ločljivost: %1" +Basic.Settings.Output.Warn.EnforceResolutionFPS.FPS="sl./s: %1" Basic.Settings.Output.VideoBitrate="Bitna hitrost slike" Basic.Settings.Output.AudioBitrate="Bitna hitrost zvoka" Basic.Settings.Output.Reconnect="Samodejno ponovno poveži" @@ -674,15 +698,15 @@ Basic.Settings.Output.CustomMuxerSettings="Prilagojene nastavitve za prepakiranj Basic.Settings.Output.NoSpaceFileName="Ustvari ime datoteke brez presledkov" Basic.Settings.Output.Adv.Rescale="Spremeni velikost izhoda" -Basic.Settings.Output.Adv.AudioTrack="Zvočna sled" +Basic.Settings.Output.Adv.AudioTrack="Zvočna steza" Basic.Settings.Output.Adv.Streaming="Pretakanje" -Basic.Settings.Output.Adv.ApplyServiceSettings="Za pretočne storitve vsili nastavitve kodirnika" -Basic.Settings.Output.Adv.Audio.Track1="1. sled" -Basic.Settings.Output.Adv.Audio.Track2="2. sled" -Basic.Settings.Output.Adv.Audio.Track3="3. sled" -Basic.Settings.Output.Adv.Audio.Track4="4. sled" -Basic.Settings.Output.Adv.Audio.Track5="5. sled" -Basic.Settings.Output.Adv.Audio.Track6="6. sled" +Basic.Settings.Output.Adv.Audio.Track1="1. steza" +Basic.Settings.Output.Adv.Audio.Track2="2. steza" +Basic.Settings.Output.Adv.Audio.Track3="3. steza" +Basic.Settings.Output.Adv.Audio.Track4="4. steza" +Basic.Settings.Output.Adv.Audio.Track5="5. steza" +Basic.Settings.Output.Adv.Audio.Track6="6. steza" +Basic.Settings.Output.Adv.TwitchVodTrack="Twitch VOD posnetek" Basic.Settings.Output.Adv.Recording="Snemanje" Basic.Settings.Output.Adv.Recording.Type="Vrsta" @@ -713,6 +737,12 @@ Basic.Settings.Output.Adv.FFmpeg.MuxerSettings="Nastavitve za prepakiranje (če Basic.Settings.Output.Adv.FFmpeg.GOPSize="Razmik med ključnimi sličicami (sličic)" Basic.Settings.Output.Adv.FFmpeg.IgnoreCodecCompat="Prikaže vse kodeke (tudi če so mogoče nezdružljivi)" +Screenshot="Izhod posnetka zaslona" +Screenshot.SourceHotkey="Izbrani vir posnetka zaslona" +Screenshot.StudioProgram="Posnetek zaslona (Program)" +Screenshot.Preview="Posnetek zaslona (Predogled)" +Screenshot.Scene="Posnetek zaslona (Scena)" +Screenshot.Source="Posnetek zaslona (Vir)" 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\n%FPS\n%CRES\n%ORES\n%VF" @@ -813,7 +843,7 @@ Basic.AdvAudio.Monitoring="Nadzor zvoka" Basic.AdvAudio.Monitoring.None="Nadzor je izklopljen" Basic.AdvAudio.Monitoring.MonitorOnly="Samo nadziraj (utišaj izhod)" Basic.AdvAudio.Monitoring.Both="Nadzor in izhod" -Basic.AdvAudio.AudioTracks="Sledi" +Basic.AdvAudio.AudioTracks="Steze" Basic.Settings.Hotkeys="Hitre tipke" Basic.Settings.Hotkeys.Pair="Kombinacije tipk, deljene s/z '%1', delujejo kot preklopniki" @@ -871,7 +901,7 @@ Push-to-talk="Pritisni in govori" SceneItemShow="Prikaži '%1'" SceneItemHide="Skrij '%1'" -OutputWarnings.NoTracksSelected="Izbrati morate vsaj eno sled" +OutputWarnings.NoTracksSelected="Izbrati morate vsaj eno stezo" OutputWarnings.MP4Recording="Opozorilo: posnetkov, shranjenih v MP4/MOV, ne bo mogoče obnoviti, če datoteka ni dokončana (npr. kot posledica \"modrega zaslona smrti\", izgube napajanja itd.). Če želite posneti več zvočnih stez, lahko uporabite MKV-ja in ga na koncu prepakirate v MP4/MOV (Datoteka → Prepakiraj posnetke)" OutputWarnings.CannotPause="Opozorilo: posnetkov ni mogoče začasno ustaviti, če je snemalni kodirnik nastavljen na \"(uporabi pretočni kodirnik)\"" @@ -917,7 +947,18 @@ Importer.AutomaticCollectionText="OBS lahko samodejno najde zbirke prizorov, ki Restart="Ponovni zagon" -NeedsRestart="OBS Studi zahteva ponovni zagon? Ponovno zaženem zdaj?" +NeedsRestart="OBS Studio zahteva ponovni zagon? Ponovno zaženem zdaj?" +ContextBar.NoSelectedSource="Ni izbranih virov" +ContextBar.ResetTransform="Ponastavi položaj, velikost in rotacijo elementa." +ContextBar.FitToCanvas="Prilagodi na sliko" +ContextBar.MediaControls.PlayMedia="Predvajaj" +ContextBar.MediaControls.PauseMedia="Pavziraj" +ContextBar.MediaControls.StopMedia="Ustavi" +ContextBar.MediaControls.RestartMedia="Ponovno žaženi" +ContextBar.MediaControls.PlaylistNext="Naprej na seznamu predvajanja" +ContextBar.MediaControls.PlaylistPrevious="Prejšnje na seznamu predvajanja" +ContextBar.MediaControls.MediaProperties="Lastnosti medijev" +ContextBar.MediaControls.BlindSeek="Pripomoček za iskanje medijev" diff --git a/UI/data/locale/sq-AL.ini b/UI/data/locale/sq-AL.ini index 3e2f042..81502e1 100644 --- a/UI/data/locale/sq-AL.ini +++ b/UI/data/locale/sq-AL.ini @@ -239,5 +239,6 @@ Basic.AutoConfig.TestPage.TestingBandwidth.Server="Duke testuar bandwithin per: + diff --git a/UI/data/locale/sr-CS.ini b/UI/data/locale/sr-CS.ini index 18b7bfc..84641ad 100644 --- a/UI/data/locale/sr-CS.ini +++ b/UI/data/locale/sr-CS.ini @@ -316,8 +316,6 @@ Deinterlacing.Yadif2x="Yadif 2x" Deinterlacing.TopFieldFirst="Prvo gornje polje" Deinterlacing.BottomFieldFirst="Prvo donje polje" -VolControl.SliderUnmuted="Slajder jačine zvuka za '%1': %2" -VolControl.SliderMuted="Slajder jačine zvuka za '%1': %2 (trenutno isključen)" VolControl.Mute="Isključite zvuk '%1'" VolControl.Properties="Svojstva '%1'" @@ -347,6 +345,7 @@ Basic.SourceSelect.CreateNew="Napravi novi" Basic.SourceSelect.AddExisting="Dodaj postojeći" Basic.SourceSelect.AddVisible="Prikaži izvor" + Basic.PropertiesWindow="Svojstva za '%1'" Basic.PropertiesWindow.AutoSelectFormat="%1 (automatski odabir: %2)" Basic.PropertiesWindow.SelectColor="Izaberi boju" @@ -564,7 +563,6 @@ Basic.Settings.Output.Format="Format snimanja" Basic.Settings.Output.Encoder="Enkoder" Basic.Settings.Output.SelectDirectory="Odaberi direktorijum za snimanje" Basic.Settings.Output.SelectFile="Odaberi datoteku za snimanje" -Basic.Settings.Output.EnforceBitrate="Sprovedi ograničenja u protoku striming servisa" Basic.Settings.Output.Mode="Režim izlaza" Basic.Settings.Output.Mode.Simple="Jednostavno" Basic.Settings.Output.Mode.Adv="Napredno" @@ -581,8 +579,6 @@ Basic.Settings.Output.Simple.RecordingQuality.Stream="Isto kao strim" Basic.Settings.Output.Simple.RecordingQuality.Small="Visoki kvalitet, osrednja veličina datoteke" Basic.Settings.Output.Simple.RecordingQuality.HQ="Kvalitet sa neprimetnim razlikama, velika datoteka" Basic.Settings.Output.Simple.RecordingQuality.Lossless="Kvalitet bez gubitka, izričito velika datoteka" -Basic.Settings.Output.Simple.Warn.VideoBitrate="Upozorenje: Video protok strima će biti postavljen na %1, što je gornja granica za trenutni striming servis. Ako ste sigurni da želite ići preko %1, omogućite napredne opcije enkodera i isključite \"Sprovedi ograničenja u protoku striming servisa\"." -Basic.Settings.Output.Simple.Warn.AudioBitrate="Upozorenje: Zvučni protok strima će biti postavljen na %1, što je gornja granica za trenutni striming servis. Ako ste sigurni da želite ići preko %1, omogućite napredne opcije enkodera i isključite \"Sprovedi ograničenja u protoku striming servisa\"." Basic.Settings.Output.Simple.Warn.Encoder="Upozorenje: Snimanje sa softverskim enkoderom drugačijeg kvaliteta u odnosu na strim će zahtevati dodatnu procesorsku snagu ako strimujete i snimate u isto vreme." Basic.Settings.Output.Simple.Warn.Lossless="Upozorenje: Kvalitet bez gubitka stvara izričito velike datoteke! Kvalitet bez gubitka može koristiti više od 7 gigabajta prostora na disku po minutu pri visokim rezolucijama i framerate-om. Kvalitet bez gubitka nije preporučen za duže snimanje osim ako imate veliku količinu slobodnog prostora na disku." Basic.Settings.Output.Simple.Warn.Lossless.Msg="Da li ste sigurni da želite koristiti kvalitet bez gubitka?" @@ -605,7 +601,6 @@ Basic.Settings.Output.NoSpaceFileName="Stvori ime datoteke bez razmaka" Basic.Settings.Output.Adv.Rescale="Skaliraj izlaz" Basic.Settings.Output.Adv.AudioTrack="Zvučni izvor" Basic.Settings.Output.Adv.Streaming="Strimovanje" -Basic.Settings.Output.Adv.ApplyServiceSettings="Prisilna podešavanja enkodera striming servisa" Basic.Settings.Output.Adv.Audio.Track1="Izvor 1" Basic.Settings.Output.Adv.Audio.Track2="Izvor 2" Basic.Settings.Output.Adv.Audio.Track3="Izvor 3" diff --git a/UI/data/locale/sr-SP.ini b/UI/data/locale/sr-SP.ini index cc5ad60..6ec5ccb 100644 --- a/UI/data/locale/sr-SP.ini +++ b/UI/data/locale/sr-SP.ini @@ -329,8 +329,6 @@ Deinterlacing.Yadif2x="Yadif 2x" Deinterlacing.TopFieldFirst="Прво горње поље" Deinterlacing.BottomFieldFirst="Прво доње поље" -VolControl.SliderUnmuted="Слајдер јачине звука за '%1': %2" -VolControl.SliderMuted="Слајдер јачине звука за '%1': %2 (тренутно искључен)" VolControl.Mute="Искључите звук '%1'" VolControl.Properties="Својства '%1'" @@ -360,6 +358,7 @@ Basic.SourceSelect.CreateNew="Направи нови" Basic.SourceSelect.AddExisting="Додај постојећи" Basic.SourceSelect.AddVisible="Прикажи извор" + Basic.PropertiesWindow="Својства за '%1'" Basic.PropertiesWindow.AutoSelectFormat="%1 (аутоматски одабир: %2)" Basic.PropertiesWindow.SelectColor="Изабери боју" @@ -582,7 +581,6 @@ 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="Напредно" @@ -599,8 +597,6 @@ 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 гигабајта простора на диску по минуту при високим резолуцијама и framerate-ом. Квалитет без губитка није препоручен за дуже снимање осим ако имате велику количину слободног простора на диску." Basic.Settings.Output.Simple.Warn.Lossless.Msg="Да ли сте сигурни да желите користити квалитет без губитка?" @@ -623,7 +619,6 @@ 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" diff --git a/UI/data/locale/sv-SE.ini b/UI/data/locale/sv-SE.ini index 238662d..40751b4 100644 --- a/UI/data/locale/sv-SE.ini +++ b/UI/data/locale/sv-SE.ini @@ -93,6 +93,7 @@ LockVolume="Lås volym" LogViewer="Loggvisare" ShowOnStartup="Visa vid uppstart" OpenFile="Öppna fil" +AddValue="Lägg till %1" AlreadyRunning.Title="OBS körs redan" AlreadyRunning.Text="OBS körs redan! Såvida du gjorde detta med flit, stäng ned alla befintliga instanser av OBS innan du försöker köra en ny instans. Om du har minimerat OBS till systemfältet, kontroller om det fortfarande körs där." @@ -112,7 +113,7 @@ Auth.Authing.Title="Autentiserar..." Auth.Authing.Text="Autentiserar med %1, var god vänta..." Auth.AuthFailure.Title="Autentiseringsfel" Auth.AuthFailure.Text="Misslyckades att autentisera med %1:\n\n%2: %3" -Auth.InvalidScope.Title="Autentisering krävs" +Auth.InvalidScope.Title="Verifiering krävs" Auth.InvalidScope.Text="Autentiseringskraven för %1 har ändrats. Vissa funktioner kanske inte är tillgängliga." Auth.LoadingChannel.Title="Läser in kanalinformation..." Auth.LoadingChannel.Text="Läser in kanalinformation för %1, var god vänta..." @@ -160,6 +161,7 @@ Basic.AutoConfig.StreamPage.DisconnectAccount="Koppla från konto" Basic.AutoConfig.StreamPage.DisconnectAccount.Confirm.Title="Koppla från konto?" Basic.AutoConfig.StreamPage.DisconnectAccount.Confirm.Text="Denna ändring kommer tillämpas direkt. Är du säker på att du vill koppla från ditt konto?" Basic.AutoConfig.StreamPage.GetStreamKey="Hämta strömnyckel" +Basic.AutoConfig.StreamPage.MoreInfo="Mer information" Basic.AutoConfig.StreamPage.UseStreamKey="Använd strömnyckel" Basic.AutoConfig.StreamPage.Service="Tjänst" Basic.AutoConfig.StreamPage.Service.ShowAll="Visa alla..." @@ -186,16 +188,16 @@ Basic.AutoConfig.TestPage.TestingRes.Fail="Misslyckades att starta kodaren" Basic.AutoConfig.TestPage.TestingRes.Resolution="Testar %1x%2 i %3 bilder per sekund..." Basic.AutoConfig.TestPage.Result.StreamingEncoder="Strömningskodare" Basic.AutoConfig.TestPage.Result.RecordingEncoder="Inspelningskodare" -Basic.AutoConfig.TestPage.Result.Header="Programmet har bestämt att dessa uppskattade inställningar är de mest idealiska för dig:" -Basic.AutoConfig.TestPage.Result.Footer="För att använda dessa inställningar, klicka på Verkställ inställningar. För att omkonfigurera guiden och försöka igen, klicka på Tillbaka. För att konfigurera inställningarna manuellt, klicka på Avbryt och öppna Inställningar." -Basic.AutoConfig.Info="Autokonfigurationsguiden bestämmer de bästa inställningarna baserat på dina datorspecifikationer och din internethastighet." +Basic.AutoConfig.TestPage.Result.Header="Programmet har uppskattat att de här inställningar är de mest idealiska för dig:" +Basic.AutoConfig.TestPage.Result.Footer="För att använda dessa inställningar, klicka på Verkställ inställningar. För att köra guiden igen, klicka på Tillbaka. För att konfigurera inställningarna manuellt, klicka på Avbryt och öppna Inställningar." +Basic.AutoConfig.Info="Autokonfigurationsguiden kommer att avgöra de bästa inställningarna baserat på din dators specifikation och din internethastighet." Basic.AutoConfig.RunAnytime="Detta kan köras när som helst via verktygsmenyn." Basic.Stats="Statistik" Basic.Stats.CPUUsage="Processoranvändning" Basic.Stats.HDDSpaceAvailable="Ledigt hårddiskutrymme" Basic.Stats.MemoryUsage="Minnesanvändning" -Basic.Stats.AverageTimeToRender="Medeltid för att rendera bildruta" +Basic.Stats.AverageTimeToRender="Medeltid för att färdigställa bildruta" Basic.Stats.SkippedFrames="Bildrutor som hoppades över p.g.a. kodningslagg" Basic.Stats.MissedFrames="Bildrutor som saknas p.g.a. renderingslagg" Basic.Stats.Output.Stream="Ström" @@ -364,8 +366,8 @@ Deinterlacing.Yadif2x="Yadif 2x" Deinterlacing.TopFieldFirst="Övre fältet först" Deinterlacing.BottomFieldFirst="Nedre fältet först" -VolControl.SliderUnmuted="Volymreglage för \"%1\": %2" -VolControl.SliderMuted="Volymreglage för \"%1\": %2 (tyst för tillfället)" +VolControl.SliderUnmuted="Volymreglage för '%1':" +VolControl.SliderMuted="Volymreglage för \"%1\": (tyst för tillfället)" VolControl.Mute="Tysta \"%1\"" VolControl.Properties="Egenskaper för \"%1\"" @@ -381,6 +383,7 @@ Basic.Main.RenameSceneCollection.Title="Byt namn på scensamling" AddProfile.Title="Lägg till profil" AddProfile.Text="Var god ange profilens namn" +AddProfile.WizardCheckbox="Visa automatisk konfigurationsguide" RenameProfile.Title="Byt namn på profilen" @@ -395,6 +398,11 @@ Basic.SourceSelect.CreateNew="Skapa ny" Basic.SourceSelect.AddExisting="Lägg till befintlig" Basic.SourceSelect.AddVisible="Gör källan synlig" +Basic.Main.Sources.Visibility="Synlighet" +Basic.Main.Sources.VisibilityDescription="Styr synligheten av \"%1\" i kanvas" +Basic.Main.Sources.Lock="Lås" +Basic.Main.Sources.LockDescription="Låser positionen och skalan av \"%1\" på kanvas" + Basic.PropertiesWindow="Egenskaper för \"%1\"" Basic.PropertiesWindow.AutoSelectFormat="%1 (välj automatiskt: %2)" Basic.PropertiesWindow.SelectColor="Välj färg" @@ -421,11 +429,11 @@ Basic.StatusBar.AttemptingReconnect="Försöker att återansluta... (försök %1 Basic.StatusBar.ReconnectSuccessful="Återanslutning lyckades" Basic.StatusBar.Delay="Fördröjning (%1 s)" Basic.StatusBar.DelayStartingIn="Fördröjning (börjar om %1 s)" -Basic.StatusBar.DelayStoppingIn="Fördröjning (stoppar efter %1 s)" +Basic.StatusBar.DelayStoppingIn="Fördröjning (stoppar om %1 s)" Basic.StatusBar.DelayStartingStoppingIn="Fördröjning (stoppar efter %1 s, börjar om %2 s)" Basic.Filters="Filter" -Basic.Filters.AsyncFilters="Audio/Video filter" +Basic.Filters.AsyncFilters="Ljud-/videofilter" Basic.Filters.AudioFilters="Ljudfilter" Basic.Filters.EffectFilters="Effektfilter" Basic.Filters.Title="Filter för \"%1\"" @@ -634,18 +642,24 @@ Basic.Settings.Stream.StreamSettingsWarning="Öppna inställningar" Basic.Settings.Stream.MissingUrlAndApiKey="Webbadress och strömnyckel saknas.\n\nÖppna inställningarna för att ange webbadressen och strömnyckeln under fliken \"Ström\"." Basic.Settings.Stream.MissingUrl="Strömadress saknas.\n\nÖppna inställningarna för att ange webbadressen under fliken \"Ström\"." Basic.Settings.Stream.MissingStreamKey="Strömnyckel saknas.\n\nÖppna inställningarna för att ange strömnyckeln under fliken \"Ström\"." +Basic.Settings.Stream.IgnoreRecommended="Ignorera strömningstjänstens rekommendationer" +Basic.Settings.Stream.IgnoreRecommended.Warn.Title="Åsidosätt rekommenderade inställningar" +Basic.Settings.Stream.IgnoreRecommended.Warn.Text="Varning: Om du ignorerar tjänstens begränsningar kan det leda till försämrad strömkvalitet eller förhindra dig från att strömma.\n\nVill du fortsätta?" +Basic.Settings.Stream.Recommended.MaxVideoBitrate="Maximal videobithastighet: %1 kbps" +Basic.Settings.Stream.Recommended.MaxAudioBitrate="Maximal ljudbithastighet: %1 kbps" +Basic.Settings.Stream.Recommended.MaxResolution="Maximal upplösning: %1" +Basic.Settings.Stream.Recommended.MaxFPS="Maximal bildfrekvens: %1" Basic.Settings.Output="Utmatning" 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.DynamicBitrate="Ändra bithastigheten dynamiskt för att hantera överbelastning" Basic.Settings.Output.DynamicBitrate.Beta="Ändra bithastigheten dynamiskt för att hantera överbelastning (beta)" Basic.Settings.Output.DynamicBitrate.TT="Istället för att kasta bildrutor för att reducera överbelastning kommer bithastigheten ändras dynamiskt.\n\nObservera att detta kan öka fördröjningen för tittare om en avsevärd belastning uppstår.\nNär bithastigheten sjunker kan det ta ett par minuter att återställas.\n\nStöds för närvarande endast för RTMP." Basic.Settings.Output.Mode="Utmatningsläge" -Basic.Settings.Output.Mode.Simple="Simpel" +Basic.Settings.Output.Mode.Simple="Enkelt" Basic.Settings.Output.Mode.Adv="Avancerat" Basic.Settings.Output.Mode.FFmpeg="FFmpeg-utmatning" Basic.Settings.Output.UseReplayBuffer="Aktivera reprisbuffert" @@ -661,18 +675,23 @@ 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.VideoBitrate="Varning: Strömmens videobithastighet kommer att ändras till %1, vilket är maxgränsen för den nuvarande strömtjänsten." +Basic.Settings.Output.Simple.Warn.AudioBitrate="Varning: Strömmens ljudbithastighet kommer att ändras till %1, vilket är maxgränsen för den nuvarande strömtjänsten." Basic.Settings.Output.Simple.Warn.CannotPause="Varning: Inspelningar kan inte pausas om inspelningskvaliteten är \"Samma som ström\"." 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.Encoder.Software="Programvara (x264)" +Basic.Settings.Output.Simple.Encoder.Software="Mjukvara (x264)" Basic.Settings.Output.Simple.Encoder.Hardware.QSV="Hårdvara (QSV)" Basic.Settings.Output.Simple.Encoder.Hardware.AMD="Hårdvara (AMD)" 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.Simple.Encoder.SoftwareLowCPU="Mjukvara (x264 med förinställning för låg processoranvändning, ökar filstorleken)" +Basic.Settings.Output.Simple.TwitchVodTrack="Twitch VOD-spår (använder spår 2)" +Basic.Settings.Output.Warn.EnforceResolutionFPS.Title="Inkompatibel upplösning/bildfrekvens" +Basic.Settings.Output.Warn.EnforceResolutionFPS.Msg="Den här strömningstjänsten stöder inte din nuvarande utdataupplösning och/eller bildfrekvens. De kommer att ändras till närmaste kompatibla värde:\n\n%1\n\nVill du fortsätta?" +Basic.Settings.Output.Warn.EnforceResolutionFPS.Resolution="Upplösning: %1" +Basic.Settings.Output.Warn.EnforceResolutionFPS.FPS="Bildfrekvens: %1" Basic.Settings.Output.VideoBitrate="Bithastighet för video" Basic.Settings.Output.AudioBitrate="Bithastighet för ljud" Basic.Settings.Output.Reconnect="Automatisk återanslutning" @@ -687,15 +706,16 @@ Basic.Settings.Output.NoSpaceFileName="Generera filnamn utan mellanrum" Basic.Settings.Output.Adv.Rescale="Skala om utmatning" Basic.Settings.Output.Adv.AudioTrack="Ljudspår" Basic.Settings.Output.Adv.Streaming="Strömning" -Basic.Settings.Output.Adv.ApplyServiceSettings="Tillämpa strömningstjänstens kodarinställningar" Basic.Settings.Output.Adv.Audio.Track1="Spår 1" Basic.Settings.Output.Adv.Audio.Track2="Spår 2" Basic.Settings.Output.Adv.Audio.Track3="Spår 3" Basic.Settings.Output.Adv.Audio.Track4="Spår 4" Basic.Settings.Output.Adv.Audio.Track5="Spår 5" Basic.Settings.Output.Adv.Audio.Track6="Spår 6" +Basic.Settings.Output.Adv.TwitchVodTrack="Twitch VOD-spår" Basic.Settings.Output.Adv.Recording="Inspelning" +Basic.Settings.Output.Adv.Recording.RecType="Inspelningstyp" Basic.Settings.Output.Adv.Recording.Type="Typ" Basic.Settings.Output.Adv.Recording.Type.Standard="Standard" Basic.Settings.Output.Adv.Recording.Type.FFmpegOutput="Anpassad utmatning (FFmpeg)" @@ -706,7 +726,7 @@ Basic.Settings.Output.Adv.FFmpeg.Type="FFmpeg-utmatningstyp" Basic.Settings.Output.Adv.FFmpeg.Type.URL="Utmatning till URL" Basic.Settings.Output.Adv.FFmpeg.Type.RecordToFile="Utmatning till fil" Basic.Settings.Output.Adv.FFmpeg.SaveFilter.Common="Vanliga inspelningsformat" -Basic.Settings.Output.Adv.FFmpeg.SaveFilter.All="Alla Filer" +Basic.Settings.Output.Adv.FFmpeg.SaveFilter.All="Alla filer" Basic.Settings.Output.Adv.FFmpeg.SavePathURL="Sökväg eller webbadress" Basic.Settings.Output.Adv.FFmpeg.Format="Kontainerformat" Basic.Settings.Output.Adv.FFmpeg.FormatAudio="Ljud" @@ -823,13 +843,18 @@ Basic.AdvAudio="Avancerade ljudinställningar" Basic.AdvAudio.ActiveOnly="Endast aktiva källor" Basic.AdvAudio.Name="Namn" Basic.AdvAudio.Volume="Volym" +Basic.AdvAudio.VolumeSource="Volym för \"%1\"" Basic.AdvAudio.Mono="Mono" +Basic.AdvAudio.MonoSource="Mononedmixning för \"%1\"" Basic.AdvAudio.Balance="Balans" +Basic.AdvAudio.BalanceSource="Balans för \"%1\"" Basic.AdvAudio.SyncOffset="Synkroniseringsavvikelse" +Basic.AdvAudio.SyncOffsetSource="Synkroniseringsförskjutning för \"%1\"" Basic.AdvAudio.Monitoring="Ljuduppspelning" Basic.AdvAudio.Monitoring.None="Monitor av" Basic.AdvAudio.Monitoring.MonitorOnly="Endast monitor (tysta utgång)" Basic.AdvAudio.Monitoring.Both="Monitor och utgång" +Basic.AdvAudio.MonitoringSource="Ljudövervakning för \"%1\"" Basic.AdvAudio.AudioTracks="Spår" Basic.Settings.Hotkeys="Kortkommandon" diff --git a/UI/data/locale/ta-IN.ini b/UI/data/locale/ta-IN.ini index bf880d3..8bf1a4c 100644 --- a/UI/data/locale/ta-IN.ini +++ b/UI/data/locale/ta-IN.ini @@ -328,8 +328,6 @@ Deinterlacing.Yadif2x="Yadif 2x" Deinterlacing.TopFieldFirst="முதலில் மேல் புலம்" Deinterlacing.BottomFieldFirst="முதலில் கீழ் புலம்" -VolControl.SliderUnmuted="ஒலியளவு நகர்வுகோல் '%1': %2" -VolControl.SliderMuted="ஒலியளவு நகர்வுகோல் '%1': %2 (தற்போது ஒலி தடுக்கப்பட்டது)" VolControl.Mute="'%1' ஒலிதடு" VolControl.Properties="'%1' பண்புகள்" @@ -359,6 +357,7 @@ Basic.SourceSelect.CreateNew="புதிதாக உருவாக்கு" Basic.SourceSelect.AddExisting="தற்போதுள்ள சேர்" Basic.SourceSelect.AddVisible="மூலத்தை காண்பி" + Basic.PropertiesWindow="'%1' பண்புகள்" Basic.PropertiesWindow.AutoSelectFormat="%1 (தானியங்குதேர்வு: %2)" Basic.PropertiesWindow.SelectColor="வண்ணம் தேர்ந்தெடு" @@ -577,7 +576,6 @@ Basic.Settings.Output.NoSpaceFileName="இடைவெளி இல்லாம 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" diff --git a/UI/data/locale/th-TH.ini b/UI/data/locale/th-TH.ini index 259aecd..1b4e950 100644 --- a/UI/data/locale/th-TH.ini +++ b/UI/data/locale/th-TH.ini @@ -37,6 +37,7 @@ SceneWindow="แสดงผลแบบหน้าต่าง (ฉาก)" SourceWindow="แสดงผลแบบหน้าต่าง (ทรัพยากร)" MultiviewProjector="แสดงผลหลายหน้าจอ (เต็มจอ)" MultiviewWindowed="แสดงผลหลายหน้าจอ (หน้าต่าง)" +ResizeProjectorWindowToContent="ปรับขนาดจอให้เท่ากับเนื้อหา" Clear="ล้าง" Revert="กลับค่าเดิม" Show="แสดง" @@ -68,6 +69,7 @@ Copy="คัดลอก" Paste="วาง" PasteReference="วาง (อ้างอิง)" PasteDuplicate="วาง (ซ้ำ)" +RemuxRecordings="กำลังบันทึก Remux" Next="ถัดไป" Back="กลับ" Defaults="ค่ามาตรฐาน" @@ -85,8 +87,10 @@ Calculating="กำลังคำนวณ..." Fullscreen="เต็มจอ" Windowed="หน้าต่าง" Percent="เปอร์เซ็นต์" +RefreshBrowser="รีเฟรช" AspectRatio="อัตราส่วนภาพ %1:%2" LockVolume="ล็อค ระดับเสียง" +OpenFile="เปิดไฟล์" AlreadyRunning.Title="OBS กำลังทำงานอยู่" AlreadyRunning.Text="โปรแกรม OBS กำลังทำงานอยู่ หากคุณไม่ต้องการดำเนินการดังกล่าวโปรดปิดโปรแกรม OBS ที่มีอยู่ ก่อนที่จะพยายามเรียกใช้อินสแตนซ์ใหม่ หากคุณตั้งค่าโปรแกรม OBS ให้ย่อเล็กสุด ให้ดูที่แถบบาร์ของระบบว่าโปรแกรมยังคงเปิดยังใช้งานอยู่หรือไม่" @@ -262,6 +266,7 @@ Basic.Main.PreviewDisabled="ภาพตัวอย่างถูกปิด Basic.SourceSelect.CreateNew="สร้างใหม่" + Basic.PropertiesWindow.SelectColor="เลือกสี" Basic.PropertiesWindow.AddFiles="เพิ่มไฟล์" diff --git a/UI/data/locale/tl-PH.ini b/UI/data/locale/tl-PH.ini index 3005ac1..f1bb57b 100644 --- a/UI/data/locale/tl-PH.ini +++ b/UI/data/locale/tl-PH.ini @@ -282,8 +282,6 @@ Deinterlacing.Yadif2x="Yadif 2x" Deinterlacing.TopFieldFirst="Itaas ang Patlang Una" Deinterlacing.BottomFieldFirst="Ibaba ang Patlang Una" -VolControl.SliderUnmuted="Dami ng islayder para sa '%1':%2" -VolControl.SliderMuted="Dami ng islayder para sa '%1':%2 (na kasalukuyang mahina)" VolControl.Mute="Mahina '%1'" VolControl.Properties="Ari-arian na para sa '%1'" @@ -313,6 +311,7 @@ Basic.SourceSelect.CreateNew="Lumikha ng bago" Basic.SourceSelect.AddExisting="Idagdag ang Umiiral na" Basic.SourceSelect.AddVisible="Palitawin ang source" + Basic.PropertiesWindow="Mga Katangian para sa '%1'" Basic.PropertiesWindow.AutoSelectFormat="%1 (autoselect: %2)" Basic.PropertiesWindow.SelectColor="Pumili ng Kulay" @@ -506,7 +505,6 @@ Basic.Settings.Output.Format="Format ng Recording" Basic.Settings.Output.Encoder="Encoder" Basic.Settings.Output.SelectDirectory="Pumili ng Recording Directory" Basic.Settings.Output.SelectFile="Pumili ng Recording File" -Basic.Settings.Output.EnforceBitrate="Ipatupad ang mga limitasyon sa serbisyo ng bitrate sa pag-stream" Basic.Settings.Output.Mode="Paraan ng Output" Basic.Settings.Output.Mode.Simple="Payak" Basic.Settings.Output.Mode.Adv="Mas Mahusay" @@ -523,8 +521,6 @@ Basic.Settings.Output.Simple.RecordingQuality.Stream="Katulad ng pag-stream" Basic.Settings.Output.Simple.RecordingQuality.Small="Mataas na Kalidad, Katamtamang Laki ng File" Basic.Settings.Output.Simple.RecordingQuality.HQ="Hindi Matukoy na Kalidad, Malaking File" Basic.Settings.Output.Simple.RecordingQuality.Lossless="Walang nabago sa Kalidad, Lubhang napakalaking File" -Basic.Settings.Output.Simple.Warn.VideoBitrate="Babala: Ang video bitrate ng pag-stream ay itatakda sa %1, na siyang mataas na limitasyon para sa pangkasalukuyang serbisyo ng pagstream. Kung sigurado kang nais mong lumagpas sa %1, paganahin ang advanced encoder options at tanggalin ang check sa \"Enforce streaming bitrate limits\"." -Basic.Settings.Output.Simple.Warn.AudioBitrate="Babala: Ang audio bitrate ng pag-stream ay itatakda sa %1, na siyang mataas na limitasyon para sa pangkasalukuyang serbisyo ng pag-strean. Kung sigurado kang nais mong lumagpas sa %1, paganahin ang advanced encoder options at tanggalin ang check sa \"Enforce streaming service bitrate limits\"." Basic.Settings.Output.Simple.Warn.Encoder="Babal: Ang pag-rekord gamit ang isang software encoder na iba ang kalidad sa pag-stream ay mangangailangan ng dagdag na pag-gamit sa CPU kung ikaw ay mag-stream at mag-rekord nang sabay." Basic.Settings.Output.Simple.Warn.Lossless="Babala: Ang kalidad na lossless ay nagbibigay ng lubhang malalaking file. Ang kalidad na lossless ay maaaring gumamit ng 7 gigabytes ng espasyo ng disk kada minuto o higit pa sa matataas na mga resolusyon o mga framerate. Ang lossless ay hindi minumungkahi para sa mga mahahabang recording maliban na lamang kung mayroon kang napakalaking espasyo sa disk na magagamit." Basic.Settings.Output.Simple.Warn.Lossless.Msg="Sigurado ka bang gusto mong gamitin ang lossless na kalidad?" @@ -546,7 +542,6 @@ Basic.Settings.Output.NoSpaceFileName="Gumawa ng Pangalan ng File nang walang Pa Basic.Settings.Output.Adv.Rescale="I-re-iskala ang Output" Basic.Settings.Output.Adv.AudioTrack="Pangsubaybay ng Audio" Basic.Settings.Output.Adv.Streaming="Anod" -Basic.Settings.Output.Adv.ApplyServiceSettings="I-enpors ang anod ng serbisyo ng mga enkoder seting" Basic.Settings.Output.Adv.Audio.Track1="Subaybayan 1" Basic.Settings.Output.Adv.Audio.Track2="Subaybayan 2" Basic.Settings.Output.Adv.Audio.Track3="Subaybayan 3" diff --git a/UI/data/locale/tr-TR.ini b/UI/data/locale/tr-TR.ini index 5c5ef8e..dedf3f6 100644 --- a/UI/data/locale/tr-TR.ini +++ b/UI/data/locale/tr-TR.ini @@ -161,6 +161,7 @@ Basic.AutoConfig.StreamPage.DisconnectAccount="Hesap Bağlantısını Kes" Basic.AutoConfig.StreamPage.DisconnectAccount.Confirm.Title="Hesap Bağlantısı Kesilsin Mi?" Basic.AutoConfig.StreamPage.DisconnectAccount.Confirm.Text="Bu değişiklik hemen uygulanacaktır. Hesabınızın bağlantısını kesmek istediğinize emin misiniz?" Basic.AutoConfig.StreamPage.GetStreamKey="Yayın Anahtarını Al" +Basic.AutoConfig.StreamPage.MoreInfo="Daha Fazla Bilgi" Basic.AutoConfig.StreamPage.UseStreamKey="Yayın Anahtarını Kullan" Basic.AutoConfig.StreamPage.Service="Hizmet" Basic.AutoConfig.StreamPage.Service.ShowAll="Tümünü Göster..." @@ -365,8 +366,8 @@ Deinterlacing.Yadif2x="Yadif 2x" Deinterlacing.TopFieldFirst="Önce Üst Alan" Deinterlacing.BottomFieldFirst="Önce Alt Alan" -VolControl.SliderUnmuted="'%1' için ses kaydırıcı: %2" -VolControl.SliderMuted="Повзунок гучності для '%1': %2 (şu anda sessiz)" +VolControl.SliderUnmuted="'%1' için ses ayarı:" +VolControl.SliderMuted="'%1' için ses ayarı: ('%1' susturuldu)" VolControl.Mute="Sessiz '%1'" VolControl.Properties="'%1' için özellikler" @@ -382,6 +383,7 @@ Basic.Main.RenameSceneCollection.Title="Sahne Koleksiyonunu Yeniden Adlandır" AddProfile.Title="Profil Ekle" AddProfile.Text="Lütfen profil isimini girin" +AddProfile.WizardCheckbox="Otomatik yapılandırma sihirbazını göster" RenameProfile.Title="Profili Yeniden Adlandır" @@ -396,6 +398,11 @@ Basic.SourceSelect.CreateNew="Yeni oluştur" Basic.SourceSelect.AddExisting="Varolanı Ekle" Basic.SourceSelect.AddVisible="Kaynağı görünür yap" +Basic.Main.Sources.Visibility="Görünürlük" +Basic.Main.Sources.VisibilityDescription="'%1' 'in tuvaldeki görünebilirliğini ayarlar" +Basic.Main.Sources.Lock="Kilitle" +Basic.Main.Sources.LockDescription="'%1' 'in tuvaldeki konumunu ve boyutunu kilitler" + Basic.PropertiesWindow="'%1' için özellikler" Basic.PropertiesWindow.AutoSelectFormat="%1(oto.seçim: %2)" Basic.PropertiesWindow.SelectColor="Renk seçin" @@ -635,13 +642,19 @@ Basic.Settings.Stream.StreamSettingsWarning="Ayarları Aç" Basic.Settings.Stream.MissingUrlAndApiKey="URL ve Akış Anahtarı eksik.\n\n ' stream ' sekmesinde URL ve Akış Anahtarını girmek için ayarları açın." Basic.Settings.Stream.MissingUrl="Akış URL'si eksik.\n\n ' Akış ' sekmesine URL’yi girmek için ayarları açın." Basic.Settings.Stream.MissingStreamKey="Akış anahtarı eksik.\n\n ' Stream ' sekmesinde stream tuşuna girmek için ayarları açın." +Basic.Settings.Stream.IgnoreRecommended="Yayın hizmeti ayar önerilerini yoksay" +Basic.Settings.Stream.IgnoreRecommended.Warn.Title="Tavsiye Edilen Ayarların Üstüne Yaz" +Basic.Settings.Stream.IgnoreRecommended.Warn.Text="Uyarı: Hizmetin kısıtlamalarını yoksaymak, düşürülmüş yayın kalitesine neden olabilir veya yayın yapmanızı engelleyebilir.\n\nDevam edilsin mi?" +Basic.Settings.Stream.Recommended.MaxVideoBitrate="En Yüksek Vidyo Bit Hızı: %1 kbps" +Basic.Settings.Stream.Recommended.MaxAudioBitrate="En Yüksek Ses Bit Hızı: %1 kbps" +Basic.Settings.Stream.Recommended.MaxResolution="En Yüksek Çözünürlük: %1" +Basic.Settings.Stream.Recommended.MaxFPS="En Yüksek FPS: %1" Basic.Settings.Output="Çıkış" Basic.Settings.Output.Format="Kayıt Biçimi" Basic.Settings.Output.Encoder="Kodlayıcı" Basic.Settings.Output.SelectDirectory="Kayıt Dizinini Seçin" Basic.Settings.Output.SelectFile="Kayıt Dosyasını Seçin" -Basic.Settings.Output.EnforceBitrate="Yayın hizmetini bit hızı sınırlarına zorla" Basic.Settings.Output.DynamicBitrate="Akışı yönetmek için bit hızını değişkenli bir biçimde değiştir" Basic.Settings.Output.DynamicBitrate.Beta="Akışı yönetmek için bit hızını değişkenli bir biçimde değiştir (Beta)" Basic.Settings.Output.DynamicBitrate.TT="Akışı azaltmak için kare hızını düşürmek yerine, bit hızını değişkenli bir biçimde değiştirir.\n\nBunun, eğer ani bir akış olursa izleyiciler için gecikme yaratabileceğini unutmayın.\nEğer bit hızı düşerse, yenilenmesi bir kaç dakika alabilir.\n\nŞu anlık sadece RTMP için destekli." @@ -662,8 +675,8 @@ 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" -Basic.Settings.Output.Simple.Warn.VideoBitrate="Uyarı: Yayın video bit hızı %1 olarak ayarlanacak, bu şu anki yayın hizmeti için üst sınırdır. Eğer %1 değerinin üstüne çıkmak istediğinizden eminseniz, gelişmiş kodlayıcı seçeneklerini etkinleştirin ve \"Yayın hizmetini bit hızı sınırlarına zorla\" işaretini kaldırın." -Basic.Settings.Output.Simple.Warn.AudioBitrate="Uyarı: Yayın audio bit hızı %1 olarak ayarlanacak, bu şu anki yayın hizmeti için üst sınırdır. Eğer %1 değerinin üstüne çıkmak istediğinizden eminseniz, gelişmiş kodlayıcı seçeneklerini etkinleştirin ve \"Yayın hizmetini bit hızı sınırlarına zorla\" işaretini kaldırın." +Basic.Settings.Output.Simple.Warn.VideoBitrate="Uyarı: Yayının vidyo bit hızı %1' e ayarlanacak, ki bu değer mevcut yayın hizmeti için üst sınırdır." +Basic.Settings.Output.Simple.Warn.AudioBitrate="Uyarı: Yayının ses bit hızı %1' e ayarlanacak, ki bu değer mevcut yayın hizmeti için üst sınırdır." Basic.Settings.Output.Simple.Warn.CannotPause="Dikkat: Kayıt kalitesi \"Yayın ile aynı\"ya ayarlanmışken kayıtlar durdurulamaz." Basic.Settings.Output.Simple.Warn.Encoder="Uyarı: Bir yazılım kodlayıcı ile yayın kalitesinden farklı kayıt yapmak eğer aynı anda hem kayıt hem de yayın yapıyorsanız ilave CPU kullanımı gerektirecektir." Basic.Settings.Output.Simple.Warn.Lossless="Uyarı: Kayıpsız kalite muazzam büyük dosya boyutları oluşturur! Kayıpsız kalite, yüksek çözünürlüklerde ve kare hızlarında, dakikada 7 gigabyte'a kadar disk alanı kullanabilir. Kayıpsız, kullanılabilir disk alanınız çok büyük değilse, uzun kayıtlar için tavsiye edilmez." @@ -674,6 +687,11 @@ Basic.Settings.Output.Simple.Encoder.Hardware.QSV="Donanım (QSV)" Basic.Settings.Output.Simple.Encoder.Hardware.AMD="Donanım (AMD)" Basic.Settings.Output.Simple.Encoder.Hardware.NVENC="Donanım (NVENC)" Basic.Settings.Output.Simple.Encoder.SoftwareLowCPU="Yazılım (x264 düşük CPU kullanım önayarı, dosya boyutunu artırır)" +Basic.Settings.Output.Simple.TwitchVodTrack="Twitch VOD Parçası (Parça 2'yi kullanır)" +Basic.Settings.Output.Warn.EnforceResolutionFPS.Title="Uyumsuz Çözünürlük/Kare Hızı" +Basic.Settings.Output.Warn.EnforceResolutionFPS.Msg="Bu yayın hizmeti, mevcut çıkış çözünürlüğünüzü ve/veya kare hızınızı desteklemiyor. Bunlar, bu değerlere en yakın uyumlu değerlerle değiştirilecektir:\n\n%1\n\nDevam etmek istiyor musunuz?" +Basic.Settings.Output.Warn.EnforceResolutionFPS.Resolution="Çözünürlük: %1" +Basic.Settings.Output.Warn.EnforceResolutionFPS.FPS="FPS: %1" Basic.Settings.Output.VideoBitrate="Video Bit Hızı" Basic.Settings.Output.AudioBitrate="Ses Bit Hızı" Basic.Settings.Output.Reconnect="Otomatik Yeniden Bağlan" @@ -688,15 +706,16 @@ Basic.Settings.Output.NoSpaceFileName="Dosya ismini boşluk olmadan oluştur" Basic.Settings.Output.Adv.Rescale="Çıkışı Yeniden Boyutlandır" Basic.Settings.Output.Adv.AudioTrack="Ses Parçası" Basic.Settings.Output.Adv.Streaming="Yayın" -Basic.Settings.Output.Adv.ApplyServiceSettings="Yayın hizmetini kodlayıcı ayarlarına zorla" Basic.Settings.Output.Adv.Audio.Track1="Parça 1" Basic.Settings.Output.Adv.Audio.Track2="Ses İzi 2" Basic.Settings.Output.Adv.Audio.Track3="Ses İzi 3" Basic.Settings.Output.Adv.Audio.Track4="Ses İzi 4" Basic.Settings.Output.Adv.Audio.Track5="Parça 5" Basic.Settings.Output.Adv.Audio.Track6="Parça 6" +Basic.Settings.Output.Adv.TwitchVodTrack="Twitch VOD Parçası" Basic.Settings.Output.Adv.Recording="Kayıt" +Basic.Settings.Output.Adv.Recording.RecType="Kaydetme Türü" 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)" @@ -824,13 +843,18 @@ Basic.AdvAudio="Gelişmiş Ses Özellikleri" Basic.AdvAudio.ActiveOnly="Sadece Etkin Kaynaklar" Basic.AdvAudio.Name="İsim" Basic.AdvAudio.Volume="Ses" +Basic.AdvAudio.VolumeSource="'%1' için ses seviyesi" Basic.AdvAudio.Mono="Mono" +Basic.AdvAudio.MonoSource="'%1' için Mono Downmix" Basic.AdvAudio.Balance="Denge" +Basic.AdvAudio.BalanceSource="'%1' için dengeleme" Basic.AdvAudio.SyncOffset="Eşitleme Uzaklığı" +Basic.AdvAudio.SyncOffsetSource="'%1' için çıktıyı senkronize et" Basic.AdvAudio.Monitoring="Ses İzleme" Basic.AdvAudio.Monitoring.None="Ekran Kapalı" Basic.AdvAudio.Monitoring.MonitorOnly="Sadece Ekran (sessiz çıkış)" Basic.AdvAudio.Monitoring.Both="Ekran ve Çıkış" +Basic.AdvAudio.MonitoringSource="'%1' için ses denetimi" Basic.AdvAudio.AudioTracks="Parçalar" Basic.Settings.Hotkeys="Kısayollar" diff --git a/UI/data/locale/uk-UA.ini b/UI/data/locale/uk-UA.ini index 8686e81..9144614 100644 --- a/UI/data/locale/uk-UA.ini +++ b/UI/data/locale/uk-UA.ini @@ -7,7 +7,7 @@ Cancel="Скасувати" Close="Закрити" Save="Зберегти" Discard="Відхилити" -Disable="Вимкнуто" +Disable="Вимкнено" Yes="Так" No="Ні" Add="Додати" @@ -48,7 +48,7 @@ New="Новий" Duplicate="Дублювати" Enable="Увімкнути" DisableOSXVSync="Вимкнути macOS V-Sync" -ResetOSXVSyncOnExit="Відновити macOS V-Sync при виході" +ResetOSXVSyncOnExit="Відновити macOS V-Sync під час виходу" HighResourceUsage="Кодування перевантажено! Треба знизити вимоги до налаштування відео або спробувати швидші налаштування енкодера." Transition="Монтажний перехід" QuickTransitions="Швидкі монтажні переходи" @@ -161,6 +161,7 @@ Basic.AutoConfig.StreamPage.DisconnectAccount="Від'єднати обліко Basic.AutoConfig.StreamPage.DisconnectAccount.Confirm.Title="Від'єднати обліковий запис?" Basic.AutoConfig.StreamPage.DisconnectAccount.Confirm.Text="Ці зміни застосуються негайно. Справді від'єднати обліковий запис?" Basic.AutoConfig.StreamPage.GetStreamKey="Отримати ключ трансляції" +Basic.AutoConfig.StreamPage.MoreInfo="Докладніше" Basic.AutoConfig.StreamPage.UseStreamKey="Використати ключ трансляції" Basic.AutoConfig.StreamPage.Service="Сервіс" Basic.AutoConfig.StreamPage.Service.ShowAll="Показати всі…" @@ -189,8 +190,8 @@ Basic.AutoConfig.TestPage.Result.StreamingEncoder="Кодувальник для Basic.AutoConfig.TestPage.Result.RecordingEncoder="Кодувальник для запису" Basic.AutoConfig.TestPage.Result.Header="Програма визначила, що такі налаштування для вас найоптимальніші:" Basic.AutoConfig.TestPage.Result.Footer="Щоб використовувати ці налаштування, натисніть кнопку «Застосувати налаштування». Щоб переналаштувати майстер та спробувати знову – натисніть кнопку «Назад». Щоб налаштувати параметри самостійно – натисніть кнопку «Скасувати» та відкрийте «Налаштування»." -Basic.AutoConfig.Info="Майстер автоконфігурації визначить найкращі налаштування на основі характеристик вашого комп'ютера та швидкості Інтернету." -Basic.AutoConfig.RunAnytime="Його можна запустити в будь-який час, в меню «Інструменти»." +Basic.AutoConfig.Info="Майстер з автоналаштування визначить найкращі параметри на основі характеристик вашого комп'ютера та швидкості Інтернету." +Basic.AutoConfig.RunAnytime="Його можна запустити в будь-який час, в меню «Засоби»." Basic.Stats="Статистика" Basic.Stats.CPUUsage="Використання ЦП" @@ -208,7 +209,7 @@ Basic.Stats.Status.Reconnecting="Перепідключення" Basic.Stats.Status.Inactive="Неактивний" Basic.Stats.Status.Active="Активовано" Basic.Stats.DroppedFrames="Пропущено кадрів (мережа)" -Basic.Stats.MegabytesSent="Загалом вийшло даних" +Basic.Stats.MegabytesSent="Загалом вихідних даних" Basic.Stats.Bitrate="Бітрейт" Basic.Stats.DiskFullIn="Диск заповниться через (прибл.)" Basic.Stats.ResetStats="Скинути статистику" @@ -365,8 +366,8 @@ Deinterlacing.Yadif2x="Yadif 2x" Deinterlacing.TopFieldFirst="Спочатку непарні рядки" Deinterlacing.BottomFieldFirst="Спочатку парні рядки" -VolControl.SliderUnmuted="Повзунок гучності для '%1': %2" -VolControl.SliderMuted="Повзунок гучності для '%1': %2 (зараз заглушено)" +VolControl.SliderUnmuted="Повзунок гучності для '%1':" +VolControl.SliderMuted="Повзунок гучності для '%1': (зараз заглушено)" VolControl.Mute="Заглушити '%1'" VolControl.Properties="Параметри '%1'" @@ -382,6 +383,7 @@ Basic.Main.RenameSceneCollection.Title="Перейменувати колекц AddProfile.Title="Додати профіль" AddProfile.Text="Будь ласка, введіть назву профілю" +AddProfile.WizardCheckbox="Показувати майстер з автоналаштування" RenameProfile.Title="Перейменувати профіль" @@ -396,6 +398,11 @@ Basic.SourceSelect.CreateNew="Створити нове" Basic.SourceSelect.AddExisting="Додати існуюче" Basic.SourceSelect.AddVisible="Зробити джерело видимим" +Basic.Main.Sources.Visibility="Видимість" +Basic.Main.Sources.VisibilityDescription="Контролює видимість '%1' на полотні" +Basic.Main.Sources.Lock="Блокувати" +Basic.Main.Sources.LockDescription="Фіксує позицію та масштаб «%1» на полотні" + Basic.PropertiesWindow="Параметри '%1'" Basic.PropertiesWindow.AutoSelectFormat="%1 (автовибір: %2)" Basic.PropertiesWindow.SelectColor="Вибрати колір" @@ -531,7 +538,7 @@ 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.Order.MoveToBottom="Перемістити вниз (&B)" Basic.MainMenu.Edit.AdvAudio="Розширені властивості аудіо (&A)" Basic.MainMenu.View="Вигляд (&V)" @@ -635,13 +642,19 @@ Basic.Settings.Stream.StreamSettingsWarning="Відкрити налаштува Basic.Settings.Stream.MissingUrlAndApiKey="URL-адреса та ключ трансляції відсутні.\n\nВідкрийте налаштування, щоб вказати URL-адресу та ключ трансляції на вкладці «Трансляція»." Basic.Settings.Stream.MissingUrl="URL-адреса трансляції відсутня.\n\nВідкрийте налаштування, щоб вказати URL-адресу трансляції на вкладці «Трансляція»." Basic.Settings.Stream.MissingStreamKey="Ключ трансляції відсутній.\n\nВідкрийте налаштування, щоб вказати ключ трансляції на вкладці «Трансляція»." +Basic.Settings.Stream.IgnoreRecommended="Нехтувати порадами служби трансляцій щодо налаштувань" +Basic.Settings.Stream.IgnoreRecommended.Warn.Title="Перевизначення рекомендованих налаштувань" +Basic.Settings.Stream.IgnoreRecommended.Warn.Text="Попередження: Нехтування обмеженнями може призвести до погіршення якості потокового відео або завадити потоковій передачі.\n\nПродовжити?" +Basic.Settings.Stream.Recommended.MaxVideoBitrate="Найбільший бітрейт відео: %1 Кбіт/с" +Basic.Settings.Stream.Recommended.MaxAudioBitrate="Найбільший бітрейт звуку: %1 Кбіт/с" +Basic.Settings.Stream.Recommended.MaxResolution="Найбільша роздільна здатність: %1" +Basic.Settings.Stream.Recommended.MaxFPS="Найбільша частота кадрів на секунду: %1" 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.DynamicBitrate="Динамічно змінювати бітрейт підлаштовуючись під мережу" Basic.Settings.Output.DynamicBitrate.Beta="Динамічно змінювати бітрейт підлаштовуючись під мережу (бета)" Basic.Settings.Output.DynamicBitrate.TT="Замість пропуску кадрів динамічно змінює бітрейт на ходу, підлаштовуючись під мережу.\n\nЗауважте, що це може збільшити затримку для глядачів, якщо є значні раптові помилки мережі.\nВідновлення бітрейту до початкового значення після падіння, може зайняти до кількох хвилин.\n\nНаразі підтримується лише для RTMP протоколу." @@ -662,8 +675,8 @@ 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.VideoBitrate="Увага: Буде встановлено бітрейт потокового відео %1, що є верхньою межею поточнї служби трансляцій." +Basic.Settings.Output.Simple.Warn.AudioBitrate="Увага: Буде встановлено бітрейт звуку %1, що є верхньою межею поточнї служби трансляцій." Basic.Settings.Output.Simple.Warn.CannotPause="Попередження: записи не можна призупиняти, якщо для якості запису встановлено значення «Така ж як у трансляції»." Basic.Settings.Output.Simple.Warn.Encoder="Попередження: запис програмним кодувальником з якістю, відмінною від якості трансляції, спричиняє додаткове навантаження на центральний процесор при одночасному використанні трансляції та запису." Basic.Settings.Output.Simple.Warn.Lossless="Попередження: якість без втрат генерує надзвичайно великі розміри файлів! Може використовуватись понад 7 гігабайтів дискового простору за хвилину при високих роздільній здатності та частоті кадрів. Якість без втрат не рекомендується для тривалого запису, хіба що у вас є дуже великий обсяг вільного дискового простору." @@ -674,6 +687,11 @@ 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 з низьким навантаженням на ЦП, збільшує розмір файлу)" +Basic.Settings.Output.Simple.TwitchVodTrack="Доріжка Twitch VOD (Використовується доріжка 2)" +Basic.Settings.Output.Warn.EnforceResolutionFPS.Title="Несумісна роздільна здатність/частота кадрів" +Basic.Settings.Output.Warn.EnforceResolutionFPS.Msg="Ця служба трансляцій не підтримує поточну роздільну здатність виводу та/або частоту кадрів. Їх буде змінено на найближче сумісне значення:\n\n%1\n\nБажаєте продовжити?" +Basic.Settings.Output.Warn.EnforceResolutionFPS.Resolution="Роздільна здатність: %1" +Basic.Settings.Output.Warn.EnforceResolutionFPS.FPS="Кадрів на секунду: %1" Basic.Settings.Output.VideoBitrate="Бітрейт відео" Basic.Settings.Output.AudioBitrate="Бітрейт аудіо" Basic.Settings.Output.Reconnect="Автоматично перепідключатися" @@ -687,16 +705,17 @@ 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.Streaming="Трансляція" 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.Audio.Track5="Доріжка 5" Basic.Settings.Output.Adv.Audio.Track6="Доріжка 6" +Basic.Settings.Output.Adv.TwitchVodTrack="Доріжка Twitch VOD" Basic.Settings.Output.Adv.Recording="Записування" +Basic.Settings.Output.Adv.Recording.RecType="Тип запису" Basic.Settings.Output.Adv.Recording.Type="Тип" Basic.Settings.Output.Adv.Recording.Type.Standard="Стандартний" Basic.Settings.Output.Adv.Recording.Type.FFmpegOutput="Власний вивід (FFmpeg)" @@ -824,13 +843,18 @@ Basic.AdvAudio="Розширені налаштування аудіо" Basic.AdvAudio.ActiveOnly="Лише активні джерела" Basic.AdvAudio.Name="Назва" Basic.AdvAudio.Volume="Гучність" +Basic.AdvAudio.VolumeSource="Гучність для «%1»" Basic.AdvAudio.Mono="Моно" +Basic.AdvAudio.MonoSource="Mono Downmix для «%1»" Basic.AdvAudio.Balance="Баланс" +Basic.AdvAudio.BalanceSource="Баланс для «%1»" Basic.AdvAudio.SyncOffset="Зсув синхронізації" +Basic.AdvAudio.SyncOffsetSource="Синхронізувати зсув для «%1»" Basic.AdvAudio.Monitoring="Прослуховування звуку" Basic.AdvAudio.Monitoring.None="Прослуховування вимкнено" Basic.AdvAudio.Monitoring.MonitorOnly="Тільки прослуховування (заглушити вивід)" Basic.AdvAudio.Monitoring.Both="Прослуховування та вивід" +Basic.AdvAudio.MonitoringSource="Моніторинг звуку для «%1»" Basic.AdvAudio.AudioTracks="Доріжки" Basic.Settings.Hotkeys="Гарячі клавіші" diff --git a/UI/data/locale/ur-PK.ini b/UI/data/locale/ur-PK.ini index 4096db0..5fef0ce 100644 --- a/UI/data/locale/ur-PK.ini +++ b/UI/data/locale/ur-PK.ini @@ -77,29 +77,49 @@ AlreadyRunning.LaunchAnyway="ویسے بھی شروع" Auth.Authing.Title="توثیق کر رہا ہے..." Auth.AuthFailure.Title="تصدیق کی ناکامی" Auth.Chat="گفتگو" +Auth.StreamInfo="نشر معلومات" +BandwidthTest.Region="مقام" +BandwidthTest.Region.US="ریاست متحد امریکہ" BandwidthTest.Region.EU="یورپ" BandwidthTest.Region.Asia="ایشیا" BandwidthTest.Region.Other="دیگر" +Basic.AutoConfig.ApplySettings="تبدیلیاں لاگو کریں" Basic.AutoConfig.VideoPage="ویڈیو سیٹنگز" +Basic.AutoConfig.StreamPage="نشر معلومات" +Basic.AutoConfig.StreamPage.MoreInfo="مزید معلومات" +Basic.AutoConfig.StreamPage.Service.ShowAll="سارے دکھائیں..." +Basic.AutoConfig.StreamPage.StreamKey.LinkToSite="(لنک)" +Basic.AutoConfig.StreamPage.StreamWarning.Title="نشریات تنبیع" +Basic.Stats.Output.Stream="نشریات" +Basic.Stats.Status="حال" +Basic.Stats.Status.Live="براہِ راست" +Updater.UpdateNow="تازہ کریں" +Updater.RemindMeLater="بعد میں پتانا" +NameExists.Title="نام پہلے سے موجود ہے" +ConfirmStop.Text="کیا آپ نشریات کو بالکل روکنا چاہتے ہیں؟" +ConfirmExit.Title="و ب س بند کریں؟" +ConfirmExit.Text="و ب س فالحال چل رہا ہے، تمام نشریات اور رکوڈنگز رک گائیں گے۔ کیا آپ بالکل بند کرنا چاہتے ہیں؟" +ConfirmRemove.Title="مٹان کی تصدیق" +ConfirmRemove.Text="کیا آپ بالکل '$1' کو مٹانا چاہتے ہیں؟" @@ -126,6 +146,8 @@ Basic.AutoConfig.VideoPage="ویڈیو سیٹنگز" +Basic.SourceSelect.CreateNew="نیا بنائیں" +Basic.SourceSelect.AddExisting="موجودہ استعمال کریں" @@ -137,24 +159,34 @@ Basic.AutoConfig.VideoPage="ویڈیو سیٹنگز" +Basic.Main.StopStreaming="نشریات روکیں" +Basic.Main.StoppingStreaming="نشریات روکی جا رہی ہے..." +Basic.Main.ForceStopStreaming="نشریات روکیں (اسی وقت)" +Basic.MainMenu.View="&دیدار" +Basic.MainMenu.Tools="&آلات" +Basic.MainMenu.Help="&مدد" +Basic.MainMenu.Help.Website="&ویبسائٹ پر جائیں" +Basic.Settings.Output.Adv.FFmpeg.FormatAudio="آواز" +Basic.Settings.Audio="آواز" + diff --git a/UI/data/locale/vi-VN.ini b/UI/data/locale/vi-VN.ini index 0ff2413..191fed5 100644 --- a/UI/data/locale/vi-VN.ini +++ b/UI/data/locale/vi-VN.ini @@ -51,70 +51,70 @@ DisableOSXVSync="Tắt OSX V-Sync" ResetOSXVSyncOnExit="Đặt lại OSX V-Sync khi Thoát" HighResourceUsage="Bộ mã hóa bị quá tải! Hãy xem xét giảm chất lượng video hoặc sử dụng bộ mã hóa nhanh hơn." Transition="Chuyển cảnh" -QuickTransitions="C. cảnh nhanh" +QuickTransitions="Chuyển cảnh nhanh" FadeToBlack="Đen dần" Left="Trái" Right="Phải" Top="Trên" Bottom="Dưới" -Reset="Thiết lập lại" +Reset="Cài lại" Hours="Giờ" Minutes="Phút" Seconds="Giây" -Deprecated="Dừng cập nhật" -ReplayBuffer="Replay Buffer" +Deprecated="Loại bỏ" +ReplayBuffer="Lưu trữ đệm" Import="Nhập" Export="Xuất" Copy="Chép" Paste="Dán" -PasteReference="Dán (Tham khảo)" +PasteReference="Dán (Mẫu)" PasteDuplicate="Dán (Bản sao)" -RemuxRecordings="Ghép lại các bản ghi" +RemuxRecordings="Ghép bản ghi" Next="Tiếp tục" Back="Quay lại" Defaults="Mặc định" -HideMixer="Ẩn trong bộ trộn" -TransitionOverride="Ghi đè chuyển tiếp" -None="Không có" +HideMixer="Ẩn trong Bộ trộn" +TransitionOverride="Ghi đè chuyển cảnh" +None="Không" StudioMode.Preview="Xem trước" StudioMode.Program="Chương trình" ShowInMultiview="Xem trong Đa góc nhìn" -VerticalLayout="Bố cục dọc" +VerticalLayout="Chiều dọc" Group="Nhóm" -DoNotShowAgain="Không hiện lại thông báo nữa" +DoNotShowAgain="Không hiện thị lại" Default="(Mặc định)" -Calculating="Đang tính toán..." +Calculating="Đang tính..." Fullscreen="Toàn màn hình" Windowed="Dạng cửa sổ" Percent="Phần trăm" RefreshBrowser="Làm mới" -AspectRatio="Tỉ lệ hiển thị %1:%2" +AspectRatio="Tỉ lệ khung hình %1:%2" LockVolume="Khoá âm lượng" LogViewer="Xem log" -ShowOnStartup="Hiện lên khi khởi động nguồn" +ShowOnStartup="Hiện thị khi khởi động" OpenFile="Mở tệp" AddValue="Thêm %1" -AlreadyRunning.Title="OBS đã chạy" -AlreadyRunning.Text="OBS đã chạy rồi! Trừ khi bạn muốn làm điều này, xin vui lòng tắt mọi chương trình hiện tại của OBS trước khi cố gắng chạy một chương trình mới. Nếu bạn có OBS thiết lập để thu nhỏ trên khay hệ thống, xin vui lòng kiểm tra để xem nếu nó vẫn đang chạy hay không." -AlreadyRunning.LaunchAnyway="Khởi động luôn" +AlreadyRunning.Title="OBS hiện đang chạy" +AlreadyRunning.Text="OBS hiện đang chạy! Trừ khi bạn muốn tiếp tục, xin vui lòng tắt mọi cửa sổ hiện tại của OBS trước khi cố gắng khởi chạy một cửa sổ mới. Nếu bạn để OBS ở trạng thái thu nhỏ trên thanh tác vụ, xin vui lòng kiểm tra xem ứng dụng có đang chạy hay không." +AlreadyRunning.LaunchAnyway="Tiếp tục khởi động" ChromeOS.Title="Nền tảng không được hỗ trợ" -ChromeOS.Text="Có vẻ OBS đang được chạy trên ChromeOS. Nền tảng này không được hỗ trợ" +ChromeOS.Text="Có vẻ như OBS đang được chạy trên ChromeOS. Nền tảng này không được hỗ trợ" -DockCloseWarning.Title="Đóng cửa sổ gắn đế được" -DockCloseWarning.Text="Bạn vừa đóng một cửa số gắn đế được. Nếu bạn muốn hiển thị lại lần nữa, sử dụng trình đơn Hiển thị → Thanh đế trên thanh trình đơn." +DockCloseWarning.Title="Đóng cửa sổ cố định được" +DockCloseWarning.Text="Bạn vừa đóng một cửa số cố định được. Nếu bạn muốn hiển thị lại, lựa chọn Hiển thị → Cố định trên thanh công cụ." -ExtraBrowsers="Thanh đế trình duyệt tùy chỉnh" -ExtraBrowsers.Info="Thêm thanh đế bằng cách đặt tên và URL cho nó rồi nháy nút Áp dụng hoặc Đóng để mở thanh đế. Bạn có thể thêm hoặc xóa thanh đế bất kỳ lúc nào." -ExtraBrowsers.DockName="Tên thanh đế" +ExtraBrowsers="Trình duyệt tùy chỉnh cố định" +ExtraBrowsers.Info="Thêm cố định bằng cách đặt tên và URL, rồi chọn Áp dụng hoặc Đóng để mở cố định. Bạn có thể thêm hoặc xóa cố định bất kỳ lúc nào." +ExtraBrowsers.DockName="Tên cố định" Auth.Authing.Title="Đang xác thực..." -Auth.Authing.Text="Đang xác thực với %1, chờ lát..." +Auth.Authing.Text="Đang xác thực với %1, vui lòng chờ..." Auth.AuthFailure.Title="Xác thực không thành công" Auth.AuthFailure.Text="Không xác thực được với %1:\n\n%2: %3" Auth.InvalidScope.Title="Bắt buộc phải xác thực" -Auth.InvalidScope.Text="Những yêu cầu cần có để xác thực cho %1 đã thay đổi. Một số tính năng sẽ không có dùng được." +Auth.InvalidScope.Text="Yêu cầu xác thực cho %1 đã thay đổi. Một số tính năng có thể sẽ không còn." Auth.LoadingChannel.Title="Đang tải thông tin kênh..." Auth.LoadingChannel.Text="Đang tải thông tin về kênh cho %1, chờ lát..." Auth.ChannelFailure.Title="Bị lỗi khi nạp kênh" @@ -122,9 +122,9 @@ Auth.ChannelFailure.Text="Không tải được thông tin kênh cho %1\n\n%2: % Auth.Chat="Tán gẫu" Auth.StreamInfo="Thông tin luồng phát" TwitchAuth.Stats="Thống kê Twitch" -TwitchAuth.Feed="Bảng tin hoạt động Twitch" +TwitchAuth.Feed="Bảng tin Twitch" TwitchAuth.TwoFactorFail.Title="Không thể truy vấn khóa luồng" -TwitchAuth.TwoFactorFail.Text="OBS không thể kết nối với tài khoản Twitch của ban. Hãy chắc rằng xác minh 2 lớp đã được bật ở phầncài đặt bảo mật Twitch vì điều này là cần để phát luồng." +TwitchAuth.TwoFactorFail.Text="OBS không thể kết nối với tài khoản Twitch của bạn. Hãy chắc rằng xác minh 2 lớp đã được bật ở phầncài đặt bảo mật Twitch vì điều này là cần để phát luồng." RestreamAuth.Channels="Kênh Restream" Copy.Filters="Sao chép các bộ lọc" @@ -161,6 +161,7 @@ Basic.AutoConfig.StreamPage.DisconnectAccount="Ngắt kết nối tài khoản" Basic.AutoConfig.StreamPage.DisconnectAccount.Confirm.Title="Ngắt kết nối tài khoản?" Basic.AutoConfig.StreamPage.DisconnectAccount.Confirm.Text="Thay đổi này sẽ được áp dụng ngay lập tức. Bạn có chắc là bạn muốn ngắt kết nối tài khoản của bạn?" Basic.AutoConfig.StreamPage.GetStreamKey="Lấy khóa luồng" +Basic.AutoConfig.StreamPage.MoreInfo="Thêm thông tin" Basic.AutoConfig.StreamPage.UseStreamKey="Dùng khóa luồng phát" Basic.AutoConfig.StreamPage.Service="Dịch vụ" Basic.AutoConfig.StreamPage.Service.ShowAll="Hiện tất cả..." @@ -232,7 +233,9 @@ Updater.GameCaptureActive.Text="Thư viện móc quay game hiện đang hoạt QuickTransitions.SwapScenes="Hoán đổi cảnh Xem trước/Đầu ra sau khi Chuyển cảnh" QuickTransitions.SwapScenesTT="Hoán đổi cảnh xem trước và cảnh đầu ra sau khi chuyển cảnh (nếu cảnh đầu ra gốc vẫn tồn tại).\nMọi thay đổi với cảnh đầu ra gốc sẽ không hoàn tác." QuickTransitions.DuplicateScene="Tạo bản sao cảnh" +QuickTransitions.DuplicateSceneTT="Khi chỉnh sửa trong cùng một cảnh, cho phép biến đổi bản sửa/hiển thị bản gốc mà không làm thay đổi bản xuất ra.\nĐể chỉnh sửa cấu hình bản gốc mà không thay đổi bản xuất ra, chọn 'Sao chép Bản gốc'.\nThay đổi lựa chọn này sẽ cài đặt lại bản xuất ra hiện tại (nếu bản đó vẫn còn tồn tại)." QuickTransitions.EditProperties="Bản sao nguồn" +QuickTransitions.EditPropertiesTT="Khi chỉnh sửa trong cùng một cảnh, cho phép chỉnh sửa cấu hình bản gốc mà không ảnh hưởng đến bản xuất ra.\nChức năng chỉ được sử dụng khi chọn 'Sao chép Cảnh'.\nMột vài bản gốc (như ảnh chụp hoặc phương tiện gốc) không hỗ trợ chức năng này và không thể chỉnh sửa riêng.\nThay đổi lựa chọn này sẽ cài đặt lại bản xuất ra hiện tại (nếu bản đó vẫn còn tồn tại).\n\nChú ý: Hệ thống hoặc tài nguyên video có thể được sử dụng nhiều hơn vì chức năng sao chép bản gốc này." QuickTransitions.HotkeyName="C. cảnh nhanh: %1" Basic.AddTransition="Thêm cấu hình chuyển cảnh" @@ -363,8 +366,6 @@ Deinterlacing.Yadif2x="Yadif 2x" Deinterlacing.TopFieldFirst="Trường đầu tiên" Deinterlacing.BottomFieldFirst="Trường dưới cùng trước" -VolControl.SliderUnmuted="Thanh trượt âm lượng cho '%1': %2" -VolControl.SliderMuted="Thanh trượt âm lượng cho '%1': %2 (hiện đang tắt tiếng)" VolControl.Mute="Tắt tiếng '%1'" VolControl.Properties="Thuộc tính '%1'" @@ -380,6 +381,7 @@ Basic.Main.RenameSceneCollection.Title="Đổi tên cảnh bộ sưu tập" AddProfile.Title="Thêm cấu hình" AddProfile.Text="Vui lòng nhập tên cấu hình" +AddProfile.WizardCheckbox="Hiện thuật sĩ tự cấu hình" RenameProfile.Title="Đổi tên cấu hình" @@ -394,6 +396,8 @@ Basic.SourceSelect.CreateNew="Tạo mới" Basic.SourceSelect.AddExisting="Thêm sẵn có" Basic.SourceSelect.AddVisible="Làm cho nguồn có thể nhìn thấy" +Basic.Main.Sources.Lock="Khoá" + Basic.PropertiesWindow="Thuộc tính '%1'" Basic.PropertiesWindow.AutoSelectFormat="%1 (autoselect: %2)" Basic.PropertiesWindow.SelectColor="Chọn Màu" @@ -480,6 +484,8 @@ Basic.Main.StoppingReplayBuffer="Đang dừng Replay Buffer..." Basic.Main.StopStreaming="Ngừng phát luồng" Basic.Main.StoppingStreaming="Đang dừng stream..." Basic.Main.ForceStopStreaming="Ngừng phát luồng (huỷ chậm trễ)" +Basic.Main.ShowContextBar="Hiển thị Thanh công cụ Nguồn" +Basic.Main.HideContextBar="Ẩn Thanh công cụ Nguồn" Basic.Main.StopVirtualCam="Dừng máy quay ảo" Basic.Main.Group="Nhóm %1" Basic.Main.GroupItems="Nhóm đã chọn" @@ -536,6 +542,8 @@ Basic.MainMenu.View.Docks="Thanh đế" Basic.MainMenu.View.Docks.ResetUI="Đặt lại UI" Basic.MainMenu.View.Docks.LockUI="Khóa UI" Basic.MainMenu.View.Docks.CustomBrowserDocks="Thanh đế trình duyệt tùy chỉnh..." +Basic.MainMenu.View.ListboxToolbars="Danh sách nút Cảnh/Nguồn" +Basic.MainMenu.View.ContextBar="Thanh công cụ Nguồn" Basic.MainMenu.View.SceneTransitions="Chuyển cảnh" Basic.MainMenu.View.SourceIcons="B&iểu tượng nguồn" Basic.MainMenu.View.StatusBar="Thanh trạng thái (&S)" @@ -585,6 +593,8 @@ Basic.Settings.General.ProjectorAlwaysOnTop="Làm cho màn chiếu luôn luôn t Basic.Settings.General.Snapping="Chụp liên kết nguồn" Basic.Settings.General.ScreenSnapping="Nguồn Snap đến cạnh màn hình" Basic.Settings.General.CenterSnapping="Chụp nguồn vào trung tâm ngang và dọc" +Basic.Settings.General.SourceSnapping="Kéo nguồn tới các nguồn khác" +Basic.Settings.General.SnapDistance="Độ nhạy kéo" Basic.Settings.General.RecordWhenStreaming="Tự động ghi hình khi phát luồng" Basic.Settings.General.KeepRecordingWhenStreamStops="Quay tiếp khi dừng stream" Basic.Settings.General.ReplayBufferWhileStreaming="Tự động bắt đầu replay buffer khi stream" @@ -592,10 +602,14 @@ Basic.Settings.General.KeepReplayBufferStreamStops="Để replay buffer tiếp t Basic.Settings.General.SysTray="Khay hệ thống" Basic.Settings.General.SysTrayWhenStarted="Thu nhỏ về khay hệ thống khi bắt đầu" Basic.Settings.General.SystemTrayHideMinimize="Luôn luôn thu nhỏ về khay hệ thống thay vì thanh tác vụ" +Basic.Settings.General.SaveProjectors="Lưu màn hình chiếu khi thoát" Basic.Settings.General.Preview="Xem trước" Basic.Settings.General.OverflowHidden="Ẩn phần tràn" +Basic.Settings.General.OverflowAlwaysVisible="Luôn hiện thị tràn khung hình" +Basic.Settings.General.OverflowSelectionHidden="Hiển thị tràn khung hình khi không thấy nguồn" Basic.Settings.General.Importers="Bộ nhập" Basic.Settings.General.AutomaticCollectionSearch="Tìm kiếm các bộ sưu tập cảnh ở các địa điểm đã biết khi nhập" +Basic.Settings.General.SwitchOnDoubleClick="Nháy đúp chuột để chuyển cảnh" Basic.Settings.General.StudioPortraitLayout="Bật bố cục theo chiều ngang/dọc" Basic.Settings.General.TogglePreviewProgramLabels="Hiện nhãn của xem trước/chương trình" Basic.Settings.General.Multiview="Đa góc nhìn" @@ -623,13 +637,17 @@ Basic.Settings.Stream.StreamSettingsWarning="Mở thiết đặt" Basic.Settings.Stream.MissingUrlAndApiKey="URL và khoá luồng đang bị thiếu.\n\nMở thiết đặt để nhập URL và khoá luồng trong thẻ 'luồng'." Basic.Settings.Stream.MissingUrl="URL luồng đang bị thiếu. \n\nMở thiết đặt để nhập URL trong thẻ 'Luồng'." Basic.Settings.Stream.MissingStreamKey="Khoá luồng đang bị thiếu. \n\nMở thiết đặt để nhập khoả luồng trong thẻ 'Luồng'." +Basic.Settings.Stream.Recommended.MaxResolution="Độ phân giải tối đa: %1" +Basic.Settings.Stream.Recommended.MaxFPS="FPS tối đa: %1" Basic.Settings.Output="Đầu ra" Basic.Settings.Output.Format="Định dạng ghi âm" Basic.Settings.Output.Encoder="Mã hóa" Basic.Settings.Output.SelectDirectory="Chọn thư mục ghi âm" Basic.Settings.Output.SelectFile="Chọn tập tin ghi âm" -Basic.Settings.Output.EnforceBitrate="Bắt buộc phải giới hạn tốc độ bit dịch vụ phát luồng" +Basic.Settings.Output.DynamicBitrate="Điều chỉnh tốc độ bit linh hoạt để quản lý tắc nghẽn mạng" +Basic.Settings.Output.DynamicBitrate.Beta="Điều chỉnh tốc độ bit linh hoạt để quản lý tắc nghẽn mạng (Bản Beta)" +Basic.Settings.Output.DynamicBitrate.TT="Thay vì hạ khung hình để giảm tắc nghẽn mạng, có thể ngay lập tức điều chỉnh tốc độ bit linh hoạt.\n\nChú ý điều này có thể dẫn đến tăng độ trễ với người xem nếu xuất hiện một lượng tắc nghẽn lớn.\nNếu sụt tốc độ bit có thể mất một vài phút để khôi phục.\n\nHiện tại chỉ hỗ trợ RTMP." Basic.Settings.Output.Mode="Đầu ra chế độ" Basic.Settings.Output.Mode.Simple="Dễ sử dụng" Basic.Settings.Output.Mode.Adv="Nâng cao" @@ -639,6 +657,7 @@ Basic.Settings.Output.ReplayBuffer.SecondsMax="Thời gian phát lại tối đa Basic.Settings.Output.ReplayBuffer.MegabytesMax="Bộ nhớ tối đa (Megabyte)" Basic.Settings.Output.ReplayBuffer.Estimate="Ước tính bộ nhớ sử dụng: %1 MB" Basic.Settings.Output.ReplayBuffer.EstimateUnknown="Không thể ước tính sử dụng bộ nhớ. Xin vui lòng thiết lập giới hạn bộ nhớ tối đa." +Basic.Settings.Output.ReplayBuffer.Prefix="Tiền tố tên tệp lưu Replay" Basic.Settings.Output.ReplayBuffer.Suffix="Hậu tố" Basic.Settings.Output.Simple.SavePath="Đường dẫn ghi âm" Basic.Settings.Output.Simple.RecordingQuality="Chất lượng ghi âm" @@ -656,6 +675,9 @@ Basic.Settings.Output.Simple.Encoder.Hardware.QSV="Phần cứng (QSV)" Basic.Settings.Output.Simple.Encoder.Hardware.AMD="Phần cứng (AMD)" Basic.Settings.Output.Simple.Encoder.Hardware.NVENC="Phần cứng (NVENC)" Basic.Settings.Output.Simple.Encoder.SoftwareLowCPU="Phần mềm (x 264 sử dụng CPU thấp cài sẵn, tăng kích thước)" +Basic.Settings.Output.Warn.EnforceResolutionFPS.Title="Tốc độ khung hình / độ phân giải không tương thích" +Basic.Settings.Output.Warn.EnforceResolutionFPS.Resolution="Độ phân giải: %1" +Basic.Settings.Output.Warn.EnforceResolutionFPS.FPS="FPS: %1" Basic.Settings.Output.VideoBitrate="Tộc độ bit video" Basic.Settings.Output.AudioBitrate="Tốc độ bit âm thanh" Basic.Settings.Output.Reconnect="Tự động kết nối" @@ -670,7 +692,6 @@ Basic.Settings.Output.NoSpaceFileName="Tạo ra tên tập tin mà không cần Basic.Settings.Output.Adv.Rescale="Rescale đầu ra" Basic.Settings.Output.Adv.AudioTrack="Dải âm thanh" Basic.Settings.Output.Adv.Streaming="Phát luồng" -Basic.Settings.Output.Adv.ApplyServiceSettings="Thực thi cài đặt mã hóa dịch vụ trực tuyến" Basic.Settings.Output.Adv.Audio.Track1="Dải âm 1" Basic.Settings.Output.Adv.Audio.Track2="Dải âm 2" Basic.Settings.Output.Adv.Audio.Track3="Dải âm 3" @@ -679,6 +700,7 @@ Basic.Settings.Output.Adv.Audio.Track5="Dải âm 5" Basic.Settings.Output.Adv.Audio.Track6="Dải âm 6" Basic.Settings.Output.Adv.Recording="Đang ghi" +Basic.Settings.Output.Adv.Recording.RecType="Loại ghi hình" Basic.Settings.Output.Adv.Recording.Type="Loại" Basic.Settings.Output.Adv.Recording.Type.Standard="Chuản" Basic.Settings.Output.Adv.Recording.Type.FFmpegOutput="Tùy chỉnh đầu ra (FFmpeg)" @@ -708,7 +730,9 @@ Basic.Settings.Output.Adv.FFmpeg.GOPSize="Thời gian đặt Keyframe (giây)" Basic.Settings.Output.Adv.FFmpeg.IgnoreCodecCompat="Hiển thị tất cả các bộ mã hóa (ngay cả khi không tương thích)" Screenshot="Đầu ra chụp màn hình" +Screenshot.SourceHotkey="Chụp màn hình Nguồn được chọn" Screenshot.StudioProgram="Chụp màn hình (Chương trình)" +Screenshot.Preview="Chụp màn hình (Xem trước)" Screenshot.Scene="Chụp màn hình (Cảnh)" Screenshot.Source="Chụp màn hình (Nguồn)" @@ -734,6 +758,7 @@ Basic.Settings.Video.DisableAero="Vô hiệu hóa Aero" Basic.Settings.Video.DownscaleFilter.Bilinear="Bilinear (nhanh nhất, nhưng mờ nếu rộng)" Basic.Settings.Video.DownscaleFilter.Bicubic="Bicubic (Sharpened rộng, 16 mẫu)" Basic.Settings.Video.DownscaleFilter.Lanczos="Lanczos (Sharpened rộng, 36 mẫu)" +Basic.Settings.Video.DownscaleFilter.Area="Vùng (Tổng trọng số, mẫu 4/6/9)" Basic.Settings.Audio="Âm thanh" Basic.Settings.Audio.SampleRate="Tỷ lệ mẫu" @@ -743,7 +768,11 @@ Basic.Settings.Audio.MeterDecayRate="Tốc độ phân rã" Basic.Settings.Audio.MeterDecayRate.Fast="Nhanh" Basic.Settings.Audio.MeterDecayRate.Medium="Trung bình (Loại I PPM)" Basic.Settings.Audio.MeterDecayRate.Slow="Chậm (Loại II PPM)" +Basic.Settings.Audio.PeakMeterType="Loại công cụ đo cực đại" +Basic.Settings.Audio.PeakMeterType.SamplePeak="Âm thu cực đại" +Basic.Settings.Audio.PeakMeterType.TruePeak="Âm thực cực đại (Sử dụng nhiều CPU hơn)" Basic.Settings.Audio.MultiChannelWarning.Enabled="CẢNH BÁO: Âm thanh vòm đang kích hoạt." +Basic.Settings.Audio.MultichannelWarning="Khi truyền phát, hãy kiểm tra xem dịch vụ truyền phát của bạn có hỗ trợ cả âm thanh vòm tích hợp và phát lại. Facebook 360 Live là một ví dụ hỗ trợ hoàn toàn âm thanh vòm. Tuy Facebook Live và Youtube Live đều cho phép âm thanh vòm tích hợp, Facebook Live dùng bộ trộn downmix để phát âm thanh, còn Youtube Live lại xuất ra hai kênh.\n\nHệ thống lọc âm của OBS tương thích với âm thanh vòm tuy plugin bổ trợ chưa chắc được hỗ trợ." Basic.Settings.Audio.MultichannelWarning.Title="Kích hoạt âm thanh vòm?" Basic.Settings.Audio.MultichannelWarning.Confirm="Bạn có chắc chắc muốn kích hoạt âm thanh vòm?" Basic.Settings.Audio.Devices="Thiết bị âm thanh chung" @@ -776,6 +805,7 @@ Basic.Settings.Advanced.Video.ColorRange.Partial="Một phần" Basic.Settings.Advanced.Video.ColorRange.Full="Đầy đủ" Basic.Settings.Advanced.Audio.MonitoringDevice="Thiết bị theo dõi" Basic.Settings.Advanced.Audio.MonitoringDevice.Default="Mặc định" +Basic.Settings.Advanced.Audio.DisableAudioDucking="Tắt chỉnh âm của Windows" Basic.Settings.Advanced.StreamDelay="Stream trễ" Basic.Settings.Advanced.StreamDelay.Duration="Độ dài" Basic.Settings.Advanced.StreamDelay.Preserve="Giữ điểm cắt (tăng chậm trễ) khi kết nối lại" @@ -783,7 +813,12 @@ Basic.Settings.Advanced.StreamDelay.MemoryUsage="Ước tính bộ nhớ sử d Basic.Settings.Advanced.Network="Mạng" Basic.Settings.Advanced.Network.BindToIP="Liên kết với IP" Basic.Settings.Advanced.Network.EnableNewSocketLoop="Bật tối ưu hóa mạng" +Basic.Settings.Advanced.Network.EnableLowLatencyMode="Bật TCP pacing" +Basic.Settings.Advanced.Network.TCPPacing.Tooltip="Cố gắng để đầu ra của RTMP thân thiện hơn với các ứng dụng có độ trễ nhạy khác bằng cách điều tuyến tốc độ băng thông.\nĐiều này có thể gia tăng nguy cơ sụt khung hình trên đường truyền không ổn định." +Basic.Settings.Advanced.Hotkeys.HotkeyFocusBehavior="Tùy chọn sử dụng phím tắt" Basic.Settings.Advanced.Hotkeys.NeverDisableHotkeys="Không bao giờ tắt phím nóng" +Basic.Settings.Advanced.Hotkeys.DisableHotkeysInFocus="Không dùng phím tắt khi cửa sổ chính không tập trung" +Basic.Settings.Advanced.Hotkeys.DisableHotkeysOutOfFocus="Không dùng phím tắt khi cửa sổ chính được tập trung" Basic.Settings.Advanced.AutoRemux="Tự động ghép lại thành mp4" Basic.Settings.Advanced.AutoRemux.MP4="(ghi với định dạng mkv)" @@ -857,11 +892,15 @@ SceneItemShow="Hiển thị '%1'" SceneItemHide="Ẩn '%1'" OutputWarnings.NoTracksSelected="Bạn phải chọn ít nhất một dải âm" +OutputWarnings.MP4Recording="Chú ý: các bản ghi âm được lưu ở dạng MP4/MOV sẽ không thể phục hồi nếu các tập tin không thể hoàn thiện (ví dụ: như bị màn hình xanh, mất điện, vv...). Nếu bạn muốn ghi nhiều luồng âm thanh thì xem xét sử dụng MKV và remux video sang MP4/MOV sau khi hoàn thành (Tập tin → Remux video)" +OutputWarnings.CannotPause="Chú ý: Ghi video không thể được dừng lại nếu bộ mã hóa ghi hình được đặt là \"(Sử dụng bộ mã hóa truyền phát)\"" FinalScene.Title="Xóa cảnh" FinalScene.Text="Cần có ít nhất một cảnh." NoSources.Title="Không có nguồn" +NoSources.Text="Có vẻ như bạn chưa thêm video nguồn nào rồi, kết quả sẽ chỉ xuất ra màn hình đen. Bạn có chắc bạn muốn tiếp tục không?" +NoSources.Text.AddSource="Bạn có thể thêm nguồn bằng cách nhấn vào biểu tượng + dưới ô Nguồn trong của sổ chính bất cứ lúc nào." NoSources.Label="Bạn không có nguồn nào cả.\nNháy vào nút + bên dưới,\nHoặc nháy chuột phải vào đây để thêm một cái." ChangeBG="Thiết lập màu sắc" @@ -901,5 +940,15 @@ Restart="Khởi động lại" NeedsRestart="OBS Studio cần phải được khởi động lại. Bạn có muốn khởi động lại luôn không?" ContextBar.NoSelectedSource="Chưa chọn nguồn nào" +ContextBar.ResetTransform="Đặt lại chuyển đổi" +ContextBar.FitToCanvas="Vừa khung hình" +ContextBar.MediaControls.PlayMedia="Chơi phương tiện" +ContextBar.MediaControls.PauseMedia="Tạm dừng phương tiện" +ContextBar.MediaControls.StopMedia="Dừng phương tiện" +ContextBar.MediaControls.RestartMedia="Khởi động lại phương tiện" +ContextBar.MediaControls.PlaylistNext="Tiếp trong danh sách" +ContextBar.MediaControls.PlaylistPrevious="Trước trong danh sách" +ContextBar.MediaControls.MediaProperties="Cấu hình phương tiện" +ContextBar.MediaControls.BlindSeek="Công cụ tìm phương tiện" diff --git a/UI/data/locale/zh-CN.ini b/UI/data/locale/zh-CN.ini index 6a0a9e9..ab5b330 100644 --- a/UI/data/locale/zh-CN.ini +++ b/UI/data/locale/zh-CN.ini @@ -161,6 +161,7 @@ Basic.AutoConfig.StreamPage.DisconnectAccount="解除帐户连接" Basic.AutoConfig.StreamPage.DisconnectAccount.Confirm.Title="解除帐户连接?" Basic.AutoConfig.StreamPage.DisconnectAccount.Confirm.Text="此更改将立即应用。您确定要解除帐户连接吗?" Basic.AutoConfig.StreamPage.GetStreamKey="获取串流密钥" +Basic.AutoConfig.StreamPage.MoreInfo="更多信息" Basic.AutoConfig.StreamPage.UseStreamKey="使用串流密钥" Basic.AutoConfig.StreamPage.Service="服务" Basic.AutoConfig.StreamPage.Service.ShowAll="显示全部..." @@ -365,8 +366,8 @@ Deinterlacing.Yadif2x="Yadif 2x" Deinterlacing.TopFieldFirst="顶场优先" Deinterlacing.BottomFieldFirst="底场优先" -VolControl.SliderUnmuted="音量滑动条 '%1': %2" -VolControl.SliderMuted="音量滑动条 '%1': %2 (当前静音)" +VolControl.SliderUnmuted="'%1'音量滑块:" +VolControl.SliderMuted="'%1'音量滑块: (当前静音)" VolControl.Mute="静音 '%1'" VolControl.Properties="'%1' 的属性" @@ -382,6 +383,7 @@ Basic.Main.RenameSceneCollection.Title="重命名场景集合" AddProfile.Title="添加配置文件" AddProfile.Text="请输入配置文件的名称" +AddProfile.WizardCheckbox="显示自动配置向导" RenameProfile.Title="重命名配置文件" @@ -396,6 +398,11 @@ Basic.SourceSelect.CreateNew="新建" Basic.SourceSelect.AddExisting="添加现有" Basic.SourceSelect.AddVisible="使源可见" +Basic.Main.Sources.Visibility="可见性" +Basic.Main.Sources.VisibilityDescription="控制画布中 '%1' 的可见性" +Basic.Main.Sources.Lock="锁定" +Basic.Main.Sources.LockDescription="锁定画布中 '%1' 的位置和比例" + Basic.PropertiesWindow="属性 '%1'" Basic.PropertiesWindow.AutoSelectFormat="%1 (自动选择: %2)" Basic.PropertiesWindow.SelectColor="选择颜色" @@ -635,13 +642,19 @@ Basic.Settings.Stream.StreamSettingsWarning="打开设置" Basic.Settings.Stream.MissingUrlAndApiKey="URL和流密钥缺失。\n\n打开设置以在“串流”选项卡中输入URL和流密钥。" Basic.Settings.Stream.MissingUrl="缺少流的 URL。\n\n打开设置以在“流”选项卡中输入URL。" Basic.Settings.Stream.MissingStreamKey="缺少流密钥。\n\n打开设置以在“流”选项卡中输入流密钥。" +Basic.Settings.Stream.IgnoreRecommended="忽略流媒体服务的推荐设置" +Basic.Settings.Stream.IgnoreRecommended.Warn.Title="覆盖推荐设置" +Basic.Settings.Stream.IgnoreRecommended.Warn.Text="警告:忽略服务的限制可能会导致推流质量降低或阻止您进行推流。\n\n继续吗?" +Basic.Settings.Stream.Recommended.MaxVideoBitrate="最大视频比特率: %1 kbps" +Basic.Settings.Stream.Recommended.MaxAudioBitrate="最大音频比特率: %1 kbps" +Basic.Settings.Stream.Recommended.MaxResolution="最大分辨率: %1" +Basic.Settings.Stream.Recommended.MaxFPS="最大FPS: %1" 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.DynamicBitrate="动态调整比特率以应对网络拥堵" Basic.Settings.Output.DynamicBitrate.Beta="动态调整比特率以应对网络拥堵(Beta)" Basic.Settings.Output.DynamicBitrate.TT="在网络拥堵时快速动态调整比特率,而不是丢弃帧来减缓拥堵。\n\n注意:开启后,若有严重的突发网络拥堵,到观众的延迟可能会增加。\n比特率降低之后,可能需要几分钟时间才能恢复。\n\n当前只支持 RTMP 流。" @@ -662,8 +675,8 @@ 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.VideoBitrate="警告:串流视频比特率将设置为 %1,这是当前串流服务的上限。" +Basic.Settings.Output.Simple.Warn.AudioBitrate="警告:串流音频比特率将设置为 %1,这是当前串流服务的上限。" Basic.Settings.Output.Simple.Warn.CannotPause="警告:当录像质量设为“与串流画质相同”时,无法暂停录制。" Basic.Settings.Output.Simple.Warn.Encoder="警告: 同时传输流和录像, 并使用软件编码器编码与流不同的质量, 将会需要额外的CPU使用." Basic.Settings.Output.Simple.Warn.Lossless="警告:无损质量产生的文件大小非常大!无损质量在高分辨率和帧速率的情况下每分钟可使用超过 7GB 的磁盘空间。无损不适合长时间录像,除非你有很多可用的磁盘空间。" @@ -674,6 +687,11 @@ 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.Simple.TwitchVodTrack="Twitch VOD 轨道 (使用轨道 2)" +Basic.Settings.Output.Warn.EnforceResolutionFPS.Title="不兼容的分辨率/帧率" +Basic.Settings.Output.Warn.EnforceResolutionFPS.Msg="此串流服务不支持您当前的输出分辨率和/或帧率。 它们将被更改为最接近的兼容值:\n\n%1\n\n你想要继续吗?" +Basic.Settings.Output.Warn.EnforceResolutionFPS.Resolution="分辨率:%1" +Basic.Settings.Output.Warn.EnforceResolutionFPS.FPS="FPS: %1" Basic.Settings.Output.VideoBitrate="视频比特率" Basic.Settings.Output.AudioBitrate="音频比特率" Basic.Settings.Output.Reconnect="自动重连" @@ -688,15 +706,16 @@ 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.Audio.Track5="轨道 5" Basic.Settings.Output.Adv.Audio.Track6="轨道 6" +Basic.Settings.Output.Adv.TwitchVodTrack="Twitch VOD 音轨" Basic.Settings.Output.Adv.Recording="录像" +Basic.Settings.Output.Adv.Recording.RecType="录制类型" Basic.Settings.Output.Adv.Recording.Type="类型" Basic.Settings.Output.Adv.Recording.Type.Standard="标准" Basic.Settings.Output.Adv.Recording.Type.FFmpegOutput="自定义输出 (FFmpeg)" @@ -824,13 +843,18 @@ Basic.AdvAudio="高级音频属性" Basic.AdvAudio.ActiveOnly="仅活动源" Basic.AdvAudio.Name="名称" Basic.AdvAudio.Volume="音量" +Basic.AdvAudio.VolumeSource="'%1' 的音量" Basic.AdvAudio.Mono="单声道​" +Basic.AdvAudio.MonoSource="'%1' 单声道缩混" Basic.AdvAudio.Balance="平衡" +Basic.AdvAudio.BalanceSource="'%1' 平衡" Basic.AdvAudio.SyncOffset="同步偏移" +Basic.AdvAudio.SyncOffsetSource="'%1' 同步偏移量" Basic.AdvAudio.Monitoring="音频监听" Basic.AdvAudio.Monitoring.None="关闭监听" Basic.AdvAudio.Monitoring.MonitorOnly="仅监听(输出静音)" Basic.AdvAudio.Monitoring.Both="监听并输出" +Basic.AdvAudio.MonitoringSource="'%1' 的音频监测" Basic.AdvAudio.AudioTracks="轨道" Basic.Settings.Hotkeys="热键" diff --git a/UI/data/locale/zh-TW.ini b/UI/data/locale/zh-TW.ini index e8f257e..2aac75f 100644 --- a/UI/data/locale/zh-TW.ini +++ b/UI/data/locale/zh-TW.ini @@ -26,7 +26,7 @@ Mixer="音效混音器" Browse="瀏覽" Mono="單聲道" Stereo="立體聲" -DroppedFrames="拋棄影格數:%1 (%2%)" +DroppedFrames="影格遺失: %1 (%2%)" StudioProgramProjector="全螢幕投影(程式)" PreviewProjector="全螢幕投影(預覽)" SceneProjector="全螢幕投影(場景)" @@ -161,6 +161,7 @@ Basic.AutoConfig.StreamPage.DisconnectAccount="解除連結帳號" Basic.AutoConfig.StreamPage.DisconnectAccount.Confirm.Title="是否要解除連結帳號?" Basic.AutoConfig.StreamPage.DisconnectAccount.Confirm.Text="此變更將立即套用,確定斷開帳號連結?" Basic.AutoConfig.StreamPage.GetStreamKey="取得串流金鑰" +Basic.AutoConfig.StreamPage.MoreInfo="更多資訊" Basic.AutoConfig.StreamPage.UseStreamKey="使用串流金鑰" Basic.AutoConfig.StreamPage.Service="服務" Basic.AutoConfig.StreamPage.Service.ShowAll="全部顯示..." @@ -365,8 +366,8 @@ Deinterlacing.Yadif2x="Yadif 2x" Deinterlacing.TopFieldFirst="由偶數場開始" Deinterlacing.BottomFieldFirst="由奇數場開始" -VolControl.SliderUnmuted="'%1' 的音量滑桿︰ %2" -VolControl.SliderMuted="'%1' 的音量滑桿︰ %2 (目前靜音中)" +VolControl.SliderUnmuted="'%1' 的音量滑桿︰" +VolControl.SliderMuted="'%1' 的音量滑桿︰(目前靜音中)" VolControl.Mute="靜音 '%1'" VolControl.Properties="'%1' 的屬性" @@ -382,6 +383,7 @@ Basic.Main.RenameSceneCollection.Title="重新命名場景群組" AddProfile.Title="新增設定檔" AddProfile.Text="請輸入設定檔的名稱" +AddProfile.WizardCheckbox="顯示自動設定精靈" RenameProfile.Title="重新命名設定檔" @@ -396,6 +398,11 @@ Basic.SourceSelect.CreateNew="建立新來源" Basic.SourceSelect.AddExisting="加入已建立來源" Basic.SourceSelect.AddVisible="顯示來源" +Basic.Main.Sources.Visibility="可見性" +Basic.Main.Sources.VisibilityDescription="控制畫布中「%1」的可見性" +Basic.Main.Sources.Lock="鎖定" +Basic.Main.Sources.LockDescription="鎖定畫布中「%1」的位置及比例" + Basic.PropertiesWindow="屬性「%1」" Basic.PropertiesWindow.AutoSelectFormat="%1 (自動選擇: %2)" Basic.PropertiesWindow.SelectColor="選取顏色" @@ -635,13 +642,19 @@ Basic.Settings.Stream.StreamSettingsWarning="開啟設定" Basic.Settings.Stream.MissingUrlAndApiKey="缺少網址及串流金鑰。\n\n開啟設定以在「串流」分頁輸入網址及串流金鑰。" Basic.Settings.Stream.MissingUrl="缺少串流網址。\n\n開啟設定以在「串流」分頁輸入網址。" Basic.Settings.Stream.MissingStreamKey="缺少串流金鑰。\n\n開啟設定以在「串流」分頁輸入串流金鑰。" +Basic.Settings.Stream.IgnoreRecommended="忽略串流服務的建議設定" +Basic.Settings.Stream.IgnoreRecommended.Warn.Title="覆蓋建議設定" +Basic.Settings.Stream.IgnoreRecommended.Warn.Text="警告:忽略服務限制可能會導致串流品質變低或無法串流。\n\n是否繼續?" +Basic.Settings.Stream.Recommended.MaxVideoBitrate="最高視訊位元速率:%1 kbps" +Basic.Settings.Stream.Recommended.MaxAudioBitrate="最高音訊位元速率:%1 kbps" +Basic.Settings.Stream.Recommended.MaxResolution="最高解析度:%1" +Basic.Settings.Stream.Recommended.MaxFPS="最高 FPS:%1" 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.DynamicBitrate="動態調整位元速率以管理堵塞問題" Basic.Settings.Output.DynamicBitrate.Beta="動態調整位元速率以管理堵塞問題 (Beta)" Basic.Settings.Output.DynamicBitrate.TT="快速動態變更位元速率而非丟棄影格來緩解堵塞問題。\n\n註:這可能會在突發嚴重堵塞時增加觀看者的延遲。\n位元速率降低後,可能會需要幾分鐘才會恢復。\n\n目前僅支援 RTMP。" @@ -662,8 +675,8 @@ 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.VideoBitrate="警告:串流視訊位元速率將設定到目前串流服務的最高值—%1。" +Basic.Settings.Output.Simple.Warn.AudioBitrate="警告:串流音訊位元速率將設定到目前串流服務的最高值—%1。" Basic.Settings.Output.Simple.Warn.CannotPause="警告:如果錄影編碼器畫質設為「(和直播編碼器相同)」,錄影時將無法暫停。" Basic.Settings.Output.Simple.Warn.Encoder="警告:如果錄影與串流同時運作,並使用與串流不同的編碼品質設定將會增加額外的CPU使用量" Basic.Settings.Output.Simple.Warn.Lossless="警告:無損畫質將會產生非常大的檔案!無損畫質在高解析度或高影格率時,可能會每分鐘使用高達 7GB(gigabytes)的容量。除非您擁有非常大量的硬碟空間,否則不建議使用無損畫質錄製長時間的影片。" @@ -674,6 +687,11 @@ 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.Simple.TwitchVodTrack="Twitch 視訊點播軌道 (使用軌道2)" +Basic.Settings.Output.Warn.EnforceResolutionFPS.Title="不相容的解析度或影格速率" +Basic.Settings.Output.Warn.EnforceResolutionFPS.Msg="這個串流服務不支援您目前輸出之解析度和影格速率的其中一個或全部。將會變更為最接近的相容值:\n\n%1\n\n是否繼續?" +Basic.Settings.Output.Warn.EnforceResolutionFPS.Resolution="解析度:%1" +Basic.Settings.Output.Warn.EnforceResolutionFPS.FPS="FPS:%1" Basic.Settings.Output.VideoBitrate="影像位元率(kbit/s)" Basic.Settings.Output.AudioBitrate="音效位元率(kbit/s)" Basic.Settings.Output.Reconnect="自動重新連線" @@ -688,15 +706,16 @@ 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.Audio.Track5="音軌 5" Basic.Settings.Output.Adv.Audio.Track6="音軌 6" +Basic.Settings.Output.Adv.TwitchVodTrack="Twitch 視訊點播軌道" Basic.Settings.Output.Adv.Recording="錄影" +Basic.Settings.Output.Adv.Recording.RecType="錄影類型" Basic.Settings.Output.Adv.Recording.Type="類型" Basic.Settings.Output.Adv.Recording.Type.Standard="標準" Basic.Settings.Output.Adv.Recording.Type.FFmpegOutput="自訂輸出 (FFmpeg)" @@ -824,13 +843,18 @@ Basic.AdvAudio="進階音訊屬性" Basic.AdvAudio.ActiveOnly="僅使用中來源" Basic.AdvAudio.Name="名稱" Basic.AdvAudio.Volume="音量" +Basic.AdvAudio.VolumeSource="'%1' 的音量" Basic.AdvAudio.Mono="單聲道" +Basic.AdvAudio.MonoSource="'%1' 的單聲道降混" Basic.AdvAudio.Balance="聲道平衡" +Basic.AdvAudio.BalanceSource="%1 的平衡" Basic.AdvAudio.SyncOffset="同步位移" +Basic.AdvAudio.SyncOffsetSource="'%1' 的同步偏移" Basic.AdvAudio.Monitoring="音訊監測" Basic.AdvAudio.Monitoring.None="關閉監測" Basic.AdvAudio.Monitoring.MonitorOnly="僅監測(輸出為靜音)" Basic.AdvAudio.Monitoring.Both="監測和輸出" +Basic.AdvAudio.MonitoringSource="'%1' 的音訊監控" Basic.AdvAudio.AudioTracks="音軌" Basic.Settings.Hotkeys="快捷鍵" diff --git a/UI/forms/AutoConfigStreamPage.ui b/UI/forms/AutoConfigStreamPage.ui index 7eec15f..e5940b9 100644 --- a/UI/forms/AutoConfigStreamPage.ui +++ b/UI/forms/AutoConfigStreamPage.ui @@ -74,7 +74,32 @@ - + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + + Basic.AutoConfig.StreamPage.MoreInfo + + + + + diff --git a/UI/forms/NameDialog.ui b/UI/forms/NameDialog.ui deleted file mode 100644 index cdd244b..0000000 --- a/UI/forms/NameDialog.ui +++ /dev/null @@ -1,105 +0,0 @@ - - - NameDialog - - - Qt::WindowModal - - - - 0 - 0 - 555 - 102 - - - - Dialog - - - - - - - 0 - 0 - - - - TextLabel - - - true - - - - - - - - 0 - 0 - - - - - - - - - - - - 0 - 0 - - - - Qt::Horizontal - - - QDialogButtonBox::Cancel|QDialogButtonBox::Ok - - - true - - - - - - - - - buttonBox - accepted() - NameDialog - accept() - - - 257 - 94 - - - 157 - 274 - - - - - buttonBox - rejected() - NameDialog - reject() - - - 325 - 94 - - - 286 - 274 - - - - - diff --git a/UI/forms/OBSBasicFilters.ui b/UI/forms/OBSBasicFilters.ui index 572a31f..2d56961 100644 --- a/UI/forms/OBSBasicFilters.ui +++ b/UI/forms/OBSBasicFilters.ui @@ -104,6 +104,9 @@ addIconSmall + + Add + @@ -130,6 +133,9 @@ removeIconSmall + + Remove + @@ -156,6 +162,9 @@ upArrowIconSmall + + MoveUp + @@ -182,6 +191,9 @@ downArrowIconSmall + + MoveDown + @@ -280,6 +292,9 @@ addIconSmall + + Add + @@ -306,6 +321,9 @@ removeIconSmall + + Remove + @@ -332,6 +350,9 @@ upArrowIconSmall + + MoveUp + @@ -358,6 +379,9 @@ downArrowIconSmall + + MoveDown + diff --git a/UI/forms/OBSBasicSettings.ui b/UI/forms/OBSBasicSettings.ui index f4eaa36..fd53049 100644 --- a/UI/forms/OBSBasicSettings.ui +++ b/UI/forms/OBSBasicSettings.ui @@ -151,8 +151,8 @@ 0 0 - 806 - 1254 + 803 + 1026 @@ -824,10 +824,41 @@ - - - 20 - + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 20 + + + + + + + + 0 + 0 + + + + Basic.AutoConfig.StreamPage.MoreInfo + + + + @@ -1214,6 +1245,20 @@ + + + + Basic.Settings.Stream.IgnoreRecommended + + + + + + + + + + @@ -1250,8 +1295,8 @@ 0 0 - 813 - 761 + 820 + 677 @@ -1347,7 +1392,7 @@ 0 - + 0 @@ -1357,7 +1402,7 @@ Basic.Settings.Output.Adv.Streaming - + QFormLayout::AllNonFixedFieldsGrow @@ -1396,6 +1441,19 @@ + + + + Basic.Settings.Output.Encoder + + + simpleOutRecEncoder + + + + + + @@ -1478,10 +1536,7 @@ - - - - + true @@ -1494,7 +1549,10 @@ - + + + + Basic.Settings.Output.CustomEncoderSettings @@ -1504,29 +1562,9 @@ - + - - - - Basic.Settings.Output.EnforceBitrate - - - - - - - - - - Basic.Settings.Output.Encoder - - - simpleOutRecEncoder - - - @@ -1876,7 +1914,7 @@ 0 - + QFormLayout::AllNonFixedFieldsGrow @@ -1899,55 +1937,6 @@ - - - - Basic.Settings.Output.Encoder - - - advOutEncoder - - - - - - - - - - Basic.Settings.Output.Adv.ApplyServiceSettings - - - true - - - - - - - - 0 - 0 - - - - Qt::RightToLeft - - - Basic.Settings.Output.Adv.Rescale - - - - - - - false - - - true - - - @@ -2017,6 +2006,45 @@ + + + + Basic.Settings.Output.Encoder + + + advOutEncoder + + + + + + + + + + + 0 + 0 + + + + Qt::RightToLeft + + + Basic.Settings.Output.Adv.Rescale + + + + + + + false + + + true + + + @@ -2492,10 +2520,22 @@ + + + 0 + 0 + + 0 + + + 0 + 0 + + 3 @@ -2529,6 +2569,12 @@ + + + 0 + 0 + + 0 @@ -2583,7 +2629,69 @@ - + + + + + 0 + 0 + + + + + 170 + 0 + + + + Basic.Settings.Output.Adv.FFmpeg.Type + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + advOutFFType + + + + + + + + Basic.Settings.Output.Adv.FFmpeg.Type.RecordToFile + + + + + Basic.Settings.Output.Adv.FFmpeg.Type.URL + + + + + + + + Basic.Settings.Output.Adv.FFmpeg.MuxerSettings + + + advOutFFMCfg + + + + + + + + + + Basic.Settings.Output.NoSpaceFileName + + + true + + + + Basic.Settings.Output.VideoBitrate @@ -2593,7 +2701,7 @@ - + 0 @@ -2606,7 +2714,17 @@ - + + + + Basic.Settings.Output.Adv.FFmpeg.GOPSize + + + advOutFFVGOPSize + + + + 1000000000 @@ -2617,16 +2735,6 @@ - - - Basic.Settings.Output.Adv.FFmpeg.GOPSize - - - advOutFFVGOPSize - - - - @@ -2642,7 +2750,7 @@ - + false @@ -2652,14 +2760,17 @@ - + Basic.Settings.Output.Adv.FFmpeg.IgnoreCodecCompat - + + + + Basic.Settings.Output.Adv.FFmpeg.VEncoder @@ -2670,9 +2781,9 @@ - + - + Basic.Settings.Output.Adv.FFmpeg.VEncoderSettings @@ -2682,20 +2793,7 @@ - - - - - - - Basic.Settings.Output.AudioBitrate - - - advOutFFABitrate - - - - + 32 @@ -2711,14 +2809,17 @@ - - + + - Basic.Settings.Output.Adv.AudioTrack + Basic.Settings.Output.AudioBitrate + + + advOutFFABitrate - + @@ -2787,7 +2888,14 @@ - + + + + Basic.Settings.Output.Adv.AudioTrack + + + + Basic.Settings.Output.Adv.FFmpeg.AEncoder @@ -2797,10 +2905,10 @@ - + - + Basic.Settings.Output.Adv.FFmpeg.AEncoderSettings @@ -2810,70 +2918,21 @@ - + - - - - - 0 - 0 - + + + + Qt::Vertical - + - 170 - 0 + 20 + 40 - - Basic.Settings.Output.Adv.FFmpeg.Type - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - advOutFFType - - - - - - - - Basic.Settings.Output.Adv.FFmpeg.Type.RecordToFile - - - - - Basic.Settings.Output.Adv.FFmpeg.Type.URL - - - - - - - - Basic.Settings.Output.Adv.FFmpeg.MuxerSettings - - - advOutFFMCfg - - - - - - - - - - Basic.Settings.Output.NoSpaceFileName - - - true - - + @@ -3745,8 +3804,8 @@ 0 0 - 767 - 582 + 555 + 469 @@ -4266,7 +4325,7 @@ - + Basic.Settings.Video.ScaledResolution @@ -4514,7 +4573,7 @@ - + 6 @@ -4601,8 +4660,8 @@ 0 0 - 791 - 970 + 602 + 781 @@ -5476,7 +5535,6 @@ simpleOutStrEncoder simpleOutputABitrate simpleOutAdvanced - simpleOutEnforce simpleOutPreset simpleOutCustom simpleOutputPath @@ -5497,7 +5555,6 @@ advOutTrack5 advOutTrack6 advOutEncoder - advOutApplyService advOutUseRescale advOutRescale advOutRecType @@ -5803,22 +5860,6 @@ - - simpleOutAdvanced - toggled(bool) - simpleOutEnforce - setVisible(bool) - - - 251 - 64 - - - 251 - 64 - - - systemTrayEnabled toggled(bool) diff --git a/UI/forms/images/obs_256x256.png b/UI/forms/images/obs_256x256.png new file mode 100644 index 0000000000000000000000000000000000000000..2b264dde00384143e0cc9b2b03c10e7b1abf7fa3 GIT binary patch literal 163961 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 literal 0 HcmV?d00001 diff --git a/UI/forms/images/tray_active_macos.png b/UI/forms/images/tray_active_macos.png new file mode 100644 index 0000000000000000000000000000000000000000..5864c61a144189354ccc1d069478465074a3cf73 GIT binary patch literal 11588 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/plus.svg images/down.svg images/up.svg + images/obs_256x256.png images/obs.png + images/obs_macos.png images/obs_paused.png + images/obs_paused_macos.png images/tray_active.png + images/tray_active_macos.png images/expand.svg images/unlocked.svg images/locked.svg diff --git a/UI/frontend-plugins/CMakeLists.txt b/UI/frontend-plugins/CMakeLists.txt index 908b5c7..eb95ba9 100644 --- a/UI/frontend-plugins/CMakeLists.txt +++ b/UI/frontend-plugins/CMakeLists.txt @@ -1,2 +1,3 @@ add_subdirectory(decklink-output-ui) add_subdirectory(frontend-tools) +add_subdirectory(decklink-captions) diff --git a/UI/frontend-plugins/decklink-captions/CMakeLists.txt b/UI/frontend-plugins/decklink-captions/CMakeLists.txt new file mode 100644 index 0000000..e3879f7 --- /dev/null +++ b/UI/frontend-plugins/decklink-captions/CMakeLists.txt @@ -0,0 +1,44 @@ +project(decklink-captions) + +if(APPLE) + find_library(COCOA Cocoa) + include_directories(${COCOA}) +endif() + +if(UNIX AND NOT APPLE) + find_package(X11 REQUIRED) + link_libraries(${X11_LIBRARIES}) + include_directories(${X11_INCLUDE_DIR}) +endif() + +set(decklink-captions_HEADERS + decklink-captions.h + ) +set(decklink-captions_SOURCES + decklink-captions.cpp + ) +set(decklink-captions_UI + forms/captions.ui + ) + +if(APPLE) + set(decklink-captions_PLATFORM_LIBS + ${COCOA}) +endif() + +qt5_wrap_ui(decklink-captions_UI_HEADERS + ${decklink-captions_UI}) + +add_library(decklink-captions MODULE + ${decklink-captions_HEADERS} + ${decklink-captions_SOURCES} + ${decklink-captions_UI_HEADERS} + ) +target_link_libraries(decklink-captions + ${frontend-tools_PLATFORM_LIBS} + obs-frontend-api + Qt5::Widgets + libobs) +set_target_properties(decklink-captions PROPERTIES FOLDER "plugins/decklink") + +install_obs_plugin_with_data(decklink-captions data) diff --git a/config/.gitignore b/UI/frontend-plugins/decklink-captions/data/.keepme similarity index 100% rename from config/.gitignore rename to UI/frontend-plugins/decklink-captions/data/.keepme diff --git a/UI/frontend-plugins/decklink-captions/decklink-captions.cpp b/UI/frontend-plugins/decklink-captions/decklink-captions.cpp new file mode 100644 index 0000000..dc15ea3 --- /dev/null +++ b/UI/frontend-plugins/decklink-captions/decklink-captions.cpp @@ -0,0 +1,159 @@ +#include +#include +#include +#include +#include "decklink-captions.h" + +OBS_DECLARE_MODULE() +OBS_MODULE_USE_DEFAULT_LOCALE("decklink-captons", "en-US") + +struct obs_captions { + std::string source_name; + OBSWeakSource source; + + void start(); + void stop(); + + obs_captions(); + inline ~obs_captions() { stop(); } +}; + +obs_captions::obs_captions() {} + +static obs_captions *captions = nullptr; + +DecklinkCaptionsUI::DecklinkCaptionsUI(QWidget *parent) + : QDialog(parent), ui(new Ui_CaptionsDialog) +{ + ui->setupUi(this); + + setSizeGripEnabled(true); + + setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); + + auto cb = [this](obs_source_t *source) { + uint32_t caps = obs_source_get_output_flags(source); + QString name = obs_source_get_name(source); + + if (caps & OBS_SOURCE_CEA_708) + ui->source->addItem(name); + + OBSWeakSource weak = OBSGetWeakRef(source); + if (weak == captions->source) + ui->source->setCurrentText(name); + return true; + }; + + using cb_t = decltype(cb); + + ui->source->blockSignals(true); + ui->source->addItem(QStringLiteral("")); + ui->source->setCurrentIndex(0); + obs_enum_sources( + [](void *data, obs_source_t *source) { + return (*static_cast(data))(source); + }, + &cb); + ui->source->blockSignals(false); +} + +void DecklinkCaptionsUI::on_source_currentIndexChanged(int) +{ + captions->stop(); + + captions->source_name = ui->source->currentText().toUtf8().constData(); + captions->source = GetWeakSourceByName(captions->source_name.c_str()); + + captions->start(); +} + +static void caption_callback(void *param, obs_source_t *source, + const struct obs_source_cea_708 *captions) +{ + UNUSED_PARAMETER(param); + UNUSED_PARAMETER(source); + obs_output *output = obs_frontend_get_streaming_output(); + if (output) { + if (obs_frontend_streaming_active() && + obs_output_active(output)) { + obs_output_caption(output, captions); + } + obs_output_release(output); + } +} + +void obs_captions::start() +{ + OBSSource s = OBSGetStrongRef(source); + if (!s) { + //warn("Source invalid"); + return; + } + obs_source_add_caption_callback(s, caption_callback, nullptr); +} + +void obs_captions::stop() +{ + OBSSource s = OBSGetStrongRef(source); + if (s) + obs_source_remove_caption_callback(s, caption_callback, + nullptr); +} + +static void save_decklink_caption_data(obs_data_t *save_data, bool saving, + void *) +{ + if (saving) { + obs_data_t *obj = obs_data_create(); + + obs_data_set_string(obj, "source", + captions->source_name.c_str()); + + obs_data_set_obj(save_data, "decklink_captions", obj); + obs_data_release(obj); + } else { + captions->stop(); + + obs_data_t *obj = + obs_data_get_obj(save_data, "decklink_captions"); + if (!obj) + obj = obs_data_create(); + + captions->source_name = obs_data_get_string(obj, "source"); + captions->source = + GetWeakSourceByName(captions->source_name.c_str()); + obs_data_release(obj); + + captions->start(); + } +} + +void addOutputUI(void) +{ + QAction *action = (QAction *)obs_frontend_add_tools_menu_qaction( + obs_module_text("Decklink Captions")); + + captions = new obs_captions; + + auto cb = []() { + obs_frontend_push_ui_translation(obs_module_get_string); + + QWidget *window = (QWidget *)obs_frontend_get_main_window(); + + DecklinkCaptionsUI dialog(window); + dialog.exec(); + + obs_frontend_pop_ui_translation(); + }; + + obs_frontend_add_save_callback(save_decklink_caption_data, nullptr); + + action->connect(action, &QAction::triggered, cb); +} + +bool obs_module_load(void) +{ + addOutputUI(); + + return true; +} diff --git a/UI/frontend-plugins/decklink-captions/decklink-captions.h b/UI/frontend-plugins/decklink-captions/decklink-captions.h new file mode 100644 index 0000000..7554a13 --- /dev/null +++ b/UI/frontend-plugins/decklink-captions/decklink-captions.h @@ -0,0 +1,30 @@ +#include +#include +#include +#include +#include +#include "ui_captions.h" + +class DecklinkCaptionsUI : public QDialog { + Q_OBJECT +private: +public: + std::unique_ptr ui; + DecklinkCaptionsUI(QWidget *parent); + +public slots: + void on_source_currentIndexChanged(int idx); +}; + +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; +} diff --git a/UI/frontend-plugins/decklink-captions/forms/captions.ui b/UI/frontend-plugins/decklink-captions/forms/captions.ui new file mode 100644 index 0000000..f251008 --- /dev/null +++ b/UI/frontend-plugins/decklink-captions/forms/captions.ui @@ -0,0 +1,115 @@ + + + CaptionsDialog + + + + 0 + 0 + 519 + 104 + + + + Captions + + + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + Captions.Source + + + source + + + + + + + QComboBox::InsertAlphabetically + + + QComboBox::AdjustToContents + + + + + + + + + Qt::Vertical + + + + 0 + 0 + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + OK + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + accept + clicked() + CaptionsDialog + accept() + + + 268 + 331 + + + 229 + -11 + + + + + diff --git a/UI/frontend-plugins/frontend-tools/CMakeLists.txt b/UI/frontend-plugins/frontend-tools/CMakeLists.txt index c017c5f..f174793 100644 --- a/UI/frontend-plugins/frontend-tools/CMakeLists.txt +++ b/UI/frontend-plugins/frontend-tools/CMakeLists.txt @@ -81,21 +81,19 @@ if(WIN32) auto-scene-switcher-win.cpp frontend-tools.rc) - if(BUILD_CAPTIONS) - set(frontend-tools_PLATFORM_SOURCES - ${frontend-tools_PLATFORM_SOURCES} - captions.cpp - captions-handler.cpp - captions-mssapi.cpp - captions-mssapi-stream.cpp) - set(frontend-tools_PLATFORM_HEADERS - captions.hpp - captions-handler.hpp - captions-mssapi.hpp - captions-mssapi-stream.hpp) - set(frontend-tools_PLATFORM_UI - forms/captions.ui) - endif() + set(frontend-tools_PLATFORM_SOURCES + ${frontend-tools_PLATFORM_SOURCES} + captions.cpp + captions-handler.cpp + captions-mssapi.cpp + captions-mssapi-stream.cpp) + set(frontend-tools_PLATFORM_HEADERS + captions.hpp + captions-handler.hpp + captions-mssapi.hpp + captions-mssapi-stream.hpp) + set(frontend-tools_PLATFORM_UI + forms/captions.ui) elseif(APPLE) set(frontend-tools_PLATFORM_SOURCES auto-scene-switcher-osx.mm) diff --git a/UI/frontend-plugins/frontend-tools/data/locale/az-AZ.ini b/UI/frontend-plugins/frontend-tools/data/locale/az-AZ.ini index 08bf302..97eeda5 100644 --- a/UI/frontend-plugins/frontend-tools/data/locale/az-AZ.ini +++ b/UI/frontend-plugins/frontend-tools/data/locale/az-AZ.ini @@ -1,6 +1,48 @@ +SceneSwitcher="Avtomatik Səhnə Dəyişdirici" +SceneSwitcher.OnNoMatch="Heç bir pəncərəyə uyğun gəlməyəndə:" +SceneSwitcher.OnNoMatch.DontSwitch="Dəyişdirmə" +SceneSwitcher.OnNoMatch.SwitchTo="Dəyişdir:" +SceneSwitcher.CheckInterval="Aktiv pəncərə başlığını yoxla:" +SceneSwitcher.ActiveOrNotActive="Səhnə Dəyişdirici:" +InvalidRegex.Title="Etibarsız Müntəzəm İfadə" +InvalidRegex.Text="Daxil etdiyiniz müntəzəm ifadə etibarsızdır." +Active="Aktiv" +Inactive="Qeyri aktiv" +Start="Başlat" +Stop="Dayandır" +Captions="Altyazılar (Təcrübi)" +Captions.AudioSource="Səs mənbəsi" +Captions.CurrentSystemLanguage="Hazırki Sistem Dili (%1)" +Captions.Provider="Təchizatçı" +Captions.Error.GenericFail="Altyazı başladılmadı" +OutputTimer="Çıxış Vaxtölçəni" +OutputTimer.Stream="Yayımı dayandır:" +OutputTimer.Record="Yazmanı dayandır:" +OutputTimer.Stream.StoppingIn="Yayım dayandırılır:" +OutputTimer.Record.StoppingIn="Yazma dayandırılır:" +OutputTimer.Stream.EnableEverytime="Hər dəfə yayım vaxtölçənini fəallaşdır" +OutputTimer.Record.EnableEverytime="Hər dəfə yazma vaxtölçənini fəallaşdır" +OutputTimer.Record.PauseTimer="Yazmaya fasilə veriləndə vaxtölçənə də fasilə ver" +Scripts="Skriptlər" +LoadedScripts="Yüklənmiş skriptlər" +AddScripts="Skript əlavə et" +RemoveScripts="Skripti çıxart" +ReloadScripts="Skripti yenidən yüklə" +Reload="Yenidən yüklə" OpenFileLocation="Fayl yerləşməsini aç" +PythonSettings="Python Tənzimləmələri" +PythonSettings.PythonInstallPath32bit="Python Quraşdırma Yolu (32 bit)" +PythonSettings.PythonInstallPath64bit="Python Quraşdırma Yolu (64 bit)" +PythonSettings.BrowsePythonPath="Python yoluna nəzər yetir" +ScriptLogWindow="Sktript jurnalı" +Description="Açıqlama" +ScriptDescriptionLink.Text="Bu bağlantı ilkin veb səyyahında açılsın?" +ScriptDescriptionLink.Text.Url="URL: %1" +ScriptDescriptionLink.OpenURL="URL-ni aç" +FileFilter.ScriptFiles="Skript faylları" +FileFilter.AllFiles="Bütün fayllar" diff --git a/UI/frontend-plugins/frontend-tools/data/locale/de-DE.ini b/UI/frontend-plugins/frontend-tools/data/locale/de-DE.ini index 143d4b8..fda5472 100644 --- a/UI/frontend-plugins/frontend-tools/data/locale/de-DE.ini +++ b/UI/frontend-plugins/frontend-tools/data/locale/de-DE.ini @@ -33,13 +33,13 @@ RemoveScripts="Skripte entfernen" ReloadScripts="Skripte neu laden" Reload="Neu laden" OpenFileLocation="Dateipfad öffnen" -PythonSettings="Python‐Einstellungen" -PythonSettings.PythonInstallPath32bit="Python‐Installationspfad (32bit)" -PythonSettings.PythonInstallPath64bit="Python‐Installationspfad (64bit)" -PythonSettings.BrowsePythonPath="Python‐Pfad öffnen" +PythonSettings="Python-Einstellungen" +PythonSettings.PythonInstallPath32bit="Python-Installationspfad (32bit)" +PythonSettings.PythonInstallPath64bit="Python-Installationspfad (64bit)" +PythonSettings.BrowsePythonPath="Python-Pfad öffnen" ScriptLogWindow="Skriptlog" Description="Beschreibung" -ScriptDescriptionLink.Text="Diesen Link in Ihrem Standard‐Webbrowser öffnen?" +ScriptDescriptionLink.Text="Diesen Link in Ihrem Standard-Webbrowser öffnen?" ScriptDescriptionLink.Text.Url="URL: %1" ScriptDescriptionLink.OpenURL="URL öffnen" diff --git a/UI/frontend-plugins/frontend-tools/data/locale/el-GR.ini b/UI/frontend-plugins/frontend-tools/data/locale/el-GR.ini index e1a8230..c693c97 100644 --- a/UI/frontend-plugins/frontend-tools/data/locale/el-GR.ini +++ b/UI/frontend-plugins/frontend-tools/data/locale/el-GR.ini @@ -31,6 +31,8 @@ LoadedScripts="Φορτωμένες δέσμες ενεργειών" AddScripts="Προσθήκη δεσμών ενεργειών" RemoveScripts="Αφαίρεση δεσμών ενεργειών" ReloadScripts="Επαναφόρτωση δεσμών ενεργειών" +Reload="Επαναφόρτωση" +OpenFileLocation="Άνοιγμα τοποθεσίας αρχείου" PythonSettings="Ρυθμίσεις Python" PythonSettings.PythonInstallPath32bit="Χώρος εγκατάστασης Python (32bit)" PythonSettings.PythonInstallPath64bit="Χώρος εγκατάστασης Python (64bit)" @@ -38,6 +40,7 @@ PythonSettings.BrowsePythonPath="Περιήγηση τού χώρου εγκατ ScriptLogWindow="Script Log" Description="Περιγραφή" ScriptDescriptionLink.Text="Ανοίξτε αυτόν τον σύνδεσμο με το προκαθορισμένο πρόγραμα περιήγησης;" +ScriptDescriptionLink.Text.Url="Σύνδεσμος: %1" ScriptDescriptionLink.OpenURL="Άνοιγμα Συνδέσμων" FileFilter.ScriptFiles="Κρυπτογραφημένο αρχείο δέσμης ενεργειών" diff --git a/UI/frontend-plugins/frontend-tools/data/locale/eo-UY.ini b/UI/frontend-plugins/frontend-tools/data/locale/eo-UY.ini new file mode 100644 index 0000000..9368831 --- /dev/null +++ b/UI/frontend-plugins/frontend-tools/data/locale/eo-UY.ini @@ -0,0 +1,48 @@ +SceneSwitcher="Aŭtomata scen-ŝanĝilo" +SceneSwitcher.OnNoMatch="Kiam neniu fenestro kongruas:" +SceneSwitcher.OnNoMatch.DontSwitch="Ne ŝanĝu" +SceneSwitcher.OnNoMatch.SwitchTo="Ŝanĝu al:" +SceneSwitcher.CheckInterval="Kontrolu aktivan fenestro-titolon ĉiu(j)n:" +SceneSwitcher.ActiveOrNotActive="Scen-ŝanĝilo estas:" +InvalidRegex.Title="Nevalida regula esprimo" +InvalidRegex.Text="La regula esprimo, kiun vi enigis, estas nevalida." +Active="Aktiva" +Inactive="Neaktiva" +Start="Startigi" +Stop="Ĉesigi" + +Captions="Subtekstoj (eksperimenta)" +Captions.AudioSource="Sonfonto" +Captions.CurrentSystemLanguage="Aktuala sistem-lingvo (%1)" +Captions.Provider="Provizanto" +Captions.Error.GenericFail="Malsukcesis startigi subtekstojn" + +OutputTimer="Elig-prokrastilo" +OutputTimer.Stream="Ĉesi elsendi post:" +OutputTimer.Record="Ĉesi registri post:" +OutputTimer.Stream.StoppingIn="Elsendado ĉesos en:" +OutputTimer.Record.StoppingIn="Registrado ĉesos en:" +OutputTimer.Stream.EnableEverytime="Ebligi elsend-prokrastilon ĉiun fojon" +OutputTimer.Record.EnableEverytime="Ebligi registro-prokrastilon ĉiun fojon" +OutputTimer.Record.PauseTimer="Paŭzigi prokrastilon kiam registrado estas paŭzigita" + +Scripts="Skriptoj" +LoadedScripts="Ŝargitaj skriptoj" +AddScripts="Aldoni skriptojn" +RemoveScripts="Forigi skriptojn" +ReloadScripts="Reŝargi skriptojn" +Reload="Reŝargi" +OpenFileLocation="Malfermi dosierlokon" +PythonSettings="Python-agordoj" +PythonSettings.PythonInstallPath32bit="Instal-loko de Python (32-bita)" +PythonSettings.PythonInstallPath64bit="Instal-loko de Python (64-bita)" +PythonSettings.BrowsePythonPath="Malfermi Python-indikon" +ScriptLogWindow="Skript-protokolo" +Description="Priskribo" +ScriptDescriptionLink.Text="Ĉu malfermi tiun ĉi ligilon en via defaŭlta retfoliumilon?" +ScriptDescriptionLink.Text.Url="Retadreso: %1" +ScriptDescriptionLink.OpenURL="Malfermi retadreson" + +FileFilter.ScriptFiles="Skript-dosieroj" +FileFilter.AllFiles="Ĉiuj dosieroj" + diff --git a/UI/frontend-plugins/frontend-tools/data/locale/es-ES.ini b/UI/frontend-plugins/frontend-tools/data/locale/es-ES.ini index 0bc3c20..4fa4242 100644 --- a/UI/frontend-plugins/frontend-tools/data/locale/es-ES.ini +++ b/UI/frontend-plugins/frontend-tools/data/locale/es-ES.ini @@ -34,9 +34,9 @@ ReloadScripts="Recargar Scripts" Reload="Recargar" OpenFileLocation="Abrir ubicación del archivo" PythonSettings="Configuración de Python" -PythonSettings.PythonInstallPath32bit="Dirección de la instalación de Python (32bit)" -PythonSettings.PythonInstallPath64bit="Dirección de la instalación de Python (64bit)" -PythonSettings.BrowsePythonPath="Buscar Ruta de Phyton" +PythonSettings.PythonInstallPath32bit="Ruta de la instalación de Python (32 bits)" +PythonSettings.PythonInstallPath64bit="Ruta de la instalación de Python (64 bits)" +PythonSettings.BrowsePythonPath="Explorar ruta de Python" ScriptLogWindow="Registro de secuencia de comandos" Description="Descripción" ScriptDescriptionLink.Text="¿Abrir este enlace en su navegador predeterminado?" diff --git a/UI/frontend-plugins/frontend-tools/data/locale/et-EE.ini b/UI/frontend-plugins/frontend-tools/data/locale/et-EE.ini index 263d084..9dd7908 100644 --- a/UI/frontend-plugins/frontend-tools/data/locale/et-EE.ini +++ b/UI/frontend-plugins/frontend-tools/data/locale/et-EE.ini @@ -25,5 +25,11 @@ OutputTimer.Stream.EnableEverytime="Lülita voogedastuse taimer alati sisse" OutputTimer.Record.EnableEverytime="Lülita salvestus taimer alati sisse" Scripts="Skriptid" +Reload="Lae uuesti" +Description="Kirjeldus" +ScriptDescriptionLink.Text.Url="URL: %1" +ScriptDescriptionLink.OpenURL="Ava URL" +FileFilter.ScriptFiles="Skriptifailid" +FileFilter.AllFiles="Kõik failid" diff --git a/UI/frontend-plugins/frontend-tools/data/locale/eu-ES.ini b/UI/frontend-plugins/frontend-tools/data/locale/eu-ES.ini index 4c2b9b6..de2f6ba 100644 --- a/UI/frontend-plugins/frontend-tools/data/locale/eu-ES.ini +++ b/UI/frontend-plugins/frontend-tools/data/locale/eu-ES.ini @@ -31,12 +31,17 @@ LoadedScripts="Kargatutako script-ak" AddScripts="Gehitu script-ak" RemoveScripts="Kendu script-ak" ReloadScripts="Birkargatu script-ak" +Reload="Berriro kargatu" +OpenFileLocation="Artxiboaren kokapena ireki" PythonSettings="Python ezarpenak" PythonSettings.PythonInstallPath32bit="Python instalazioaren bide-izena (32bit)" PythonSettings.PythonInstallPath64bit="Python instalazioaren bide-izena (64bit)" PythonSettings.BrowsePythonPath="Arakatu Python-en bide-izena" ScriptLogWindow="Script-aren erregistroa" Description="Deskribapena" +ScriptDescriptionLink.Text="Ireki esteka hau zure nabigatzaile lehenetsian?" +ScriptDescriptionLink.Text.Url="URLa: %1" +ScriptDescriptionLink.OpenURL="Ireki web-helbidea" FileFilter.ScriptFiles="Script-aren fitxategiak" FileFilter.AllFiles="Fitxategi guztiak" diff --git a/UI/frontend-plugins/frontend-tools/data/locale/fa-IR.ini b/UI/frontend-plugins/frontend-tools/data/locale/fa-IR.ini index dac6ec2..6823fc7 100644 --- a/UI/frontend-plugins/frontend-tools/data/locale/fa-IR.ini +++ b/UI/frontend-plugins/frontend-tools/data/locale/fa-IR.ini @@ -1,24 +1,47 @@ +SceneSwitcher="تغییر صحنه خودکار" SceneSwitcher.OnNoMatch="وقتی هیچ پنجره‌ای همخوانی نداشت:" SceneSwitcher.OnNoMatch.DontSwitch="سوییچ نکن" SceneSwitcher.OnNoMatch.SwitchTo="سویچ کن به:" +SceneSwitcher.CheckInterval="عنوان پنجره فعال را هر بار بررسی کنید:" +SceneSwitcher.ActiveOrNotActive="تغییر صحنه:" +InvalidRegex.Title="عبارت منظم نامعتبر است" +InvalidRegex.Text="عبارت منظمی که وارد کرده اید نامعتبر است." Active="فعال" Inactive="غیر فعال" Start="شروع" Stop="توقف" +Captions="زیرنویس ها (تجربی)" +Captions.AudioSource="منبع صدا" +Captions.CurrentSystemLanguage="زبان سیستم فعلی (%1)" +Captions.Provider="ارائه دهنده" +Captions.Error.GenericFail="زیرنویس شروع نشد" +OutputTimer="تایمر خروجی" +OutputTimer.Stream="توقف پخش جریانی بعد از:" +OutputTimer.Record="توقف ضبط بعد از:" +OutputTimer.Stream.StoppingIn="توقف پخش جریان در:" +OutputTimer.Record.StoppingIn="متوقف کردن ضبط در:" OutputTimer.Stream.EnableEverytime="هربار زمان سنج پخش جریانی را فعال کنید" OutputTimer.Record.EnableEverytime="هربار زمان سنج ضبط را فعال کنید" +OutputTimer.Record.PauseTimer="هنگام مکث ضبط، تایمر مکث کند" Scripts="اسکریپت ها" LoadedScripts="اسکریپت های بارگیری شده" AddScripts="اضافه کردن اسکریپت ها" RemoveScripts="پاک کردن اسکریپت ها" ReloadScripts="بارگیری مجدد اسکریپت ها" +Reload="تازه‌سازی" +OpenFileLocation="بازکردن مکان فایل" PythonSettings="تنظیمات پایتون" +PythonSettings.PythonInstallPath32bit="مسیر نصب پایتون (32 بیت)" +PythonSettings.PythonInstallPath64bit="مسیر نصب پایتون (64 بیت)" PythonSettings.BrowsePythonPath="مرور مسیر پایتون" ScriptLogWindow="اسکریپت نویسی" Description="توضیحات" +ScriptDescriptionLink.Text="این پیوند را در مرورگر وب پیش فرض خود باز می کنید?" +ScriptDescriptionLink.Text.Url="نشانی: %1" +ScriptDescriptionLink.OpenURL="باز کردن نشانی" FileFilter.ScriptFiles="فایل های اسکریپت" FileFilter.AllFiles="همه‌ی فایل ها" diff --git a/UI/frontend-plugins/frontend-tools/data/locale/kab-KAB.ini b/UI/frontend-plugins/frontend-tools/data/locale/kab-KAB.ini new file mode 100644 index 0000000..8c8822c --- /dev/null +++ b/UI/frontend-plugins/frontend-tools/data/locale/kab-KAB.ini @@ -0,0 +1,48 @@ +SceneSwitcher="Asenfal awurman n usayes" +SceneSwitcher.OnNoMatch="Ma ulac asfaylu inmeɣran:" +SceneSwitcher.OnNoMatch.DontSwitch="Ur senfal ara" +SceneSwitcher.OnNoMatch.SwitchTo="Senfel ɣer:" +SceneSwitcher.CheckInterval="Selken azwel n usfaylu urmid yal:" +SceneSwitcher.ActiveOrNotActive="Asenfal n usayes:" +InvalidRegex.Title="Tanfalit talugant d tarmeɣtut" +InvalidRegex.Text="Tanfalit talugant i tsekcmeḍ d tarmeɣtut." +Active="Yermed" +Inactive="Yensa" +Start="Sekker" +Stop="Seḥbes" + +Captions="Iduzwilen (d tarmit)" +Captions.AudioSource="Aɣbalu n umeslaw" +Captions.CurrentSystemLanguage="Tutlayt tamirant n unagraw (%1)" +Captions.Provider="Aseǧǧaw" +Captions.Error.GenericFail="Asekker n twaṭṭfiwin ur yeddi ara" + +OutputTimer="Amakud n tuffɣa" +OutputTimer.Stream="Ḥbes asuddem mbaɛd:" +OutputTimer.Record="Ḥbes asekles mbaɛd:" +OutputTimer.Stream.StoppingIn="Asuddem ad iḥbes di:" +OutputTimer.Record.StoppingIn="Asekles ad iḥbes di:" +OutputTimer.Stream.EnableEverytime="Sermed amakud n usuddem yal tikkelt" +OutputTimer.Record.EnableEverytime="Sermed amakud n usekles yal tikkelt" +OutputTimer.Record.PauseTimer="Ḥbes amakud ticki yeḥbes usekles" + +Scripts="Iskripten" +LoadedScripts="Iskripten yulin" +AddScripts="Rnu iskripten" +RemoveScripts="Kkes iskripten" +ReloadScripts="Ales asali n yiskripten" +Reload="Ales asali" +OpenFileLocation="Ldi adig n ufaylu" +PythonSettings="Iɣewwaren n Python" +PythonSettings.PythonInstallPath32bit="Abrid n usbeddi n Python (32bit)" +PythonSettings.PythonInstallPath64bit="Abrid n usbeddi n Python (64bit)" +PythonSettings.BrowsePythonPath="Snirem abrid n Python" +ScriptLogWindow="Aɣmis n uskript" +Description="Aglam" +ScriptDescriptionLink.Text="Ad teldiḍ aseɣwen-agi deg yiminig n web inek m n lexṣas?" +ScriptDescriptionLink.Text.Url="URL: %1" +ScriptDescriptionLink.OpenURL="Ldi URL" + +FileFilter.ScriptFiles="Ifuyla n uskript" +FileFilter.AllFiles="Akk ifuyla" + diff --git a/UI/frontend-plugins/frontend-tools/data/locale/nb-NO.ini b/UI/frontend-plugins/frontend-tools/data/locale/nb-NO.ini index 804f39c..79eeafd 100644 --- a/UI/frontend-plugins/frontend-tools/data/locale/nb-NO.ini +++ b/UI/frontend-plugins/frontend-tools/data/locale/nb-NO.ini @@ -31,12 +31,17 @@ LoadedScripts="Innlastede skripter" AddScripts="Legg til skripter" RemoveScripts="Fjern skripter" ReloadScripts="Last inn skripter på nytt" +Reload="Oppdater" +OpenFileLocation="Åpne filplassering" PythonSettings="Python-innstillinger" PythonSettings.PythonInstallPath32bit="Python-installasjonsfilbane (32-bit)" PythonSettings.PythonInstallPath64bit="Python-installasjonsfilbane (64-bit)" PythonSettings.BrowsePythonPath="Finn Python-filbanen" ScriptLogWindow="Skripthistorikk" Description="Beskrivelse" +ScriptDescriptionLink.Text="Åpne denne lenken i standard nettleser?" +ScriptDescriptionLink.Text.Url="URL: %1" +ScriptDescriptionLink.OpenURL="Åpne URL" FileFilter.ScriptFiles="Skriptfiler" FileFilter.AllFiles="Alle filer" diff --git a/UI/frontend-plugins/frontend-tools/data/locale/pl-PL.ini b/UI/frontend-plugins/frontend-tools/data/locale/pl-PL.ini index b180527..577ad0c 100644 --- a/UI/frontend-plugins/frontend-tools/data/locale/pl-PL.ini +++ b/UI/frontend-plugins/frontend-tools/data/locale/pl-PL.ini @@ -24,7 +24,7 @@ OutputTimer.Stream.StoppingIn="Zatrzymanie streamu za:" OutputTimer.Record.StoppingIn="Zatrzymanie nagrywania za:" OutputTimer.Stream.EnableEverytime="Włącz timer streamu za każdym razem" OutputTimer.Record.EnableEverytime="Włącz timer nagrywania za każdym razem" -OutputTimer.Record.PauseTimer="Zatrzymaj czas, gdy nagrywanie jest spauzowane" +OutputTimer.Record.PauseTimer="Zatrzymaj czas, gdy nagrywanie jest zapauzowane" Scripts="Skrypty" LoadedScripts="Wczytane skrypty" diff --git a/UI/frontend-plugins/frontend-tools/data/locale/pt-BR.ini b/UI/frontend-plugins/frontend-tools/data/locale/pt-BR.ini index 8360fc0..04d4a36 100644 --- a/UI/frontend-plugins/frontend-tools/data/locale/pt-BR.ini +++ b/UI/frontend-plugins/frontend-tools/data/locale/pt-BR.ini @@ -4,16 +4,16 @@ 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á:" -InvalidRegex.Title="Expressão Regular inválida" +InvalidRegex.Title="Expressão regular inválida" InvalidRegex.Text="A expressão regular que você inseriu é inválida." Active="Ligado" Inactive="Desligado" Start="Iniciar" Stop="Parar" -Captions="Legendas (Experimental)" -Captions.AudioSource="Fonte de Áudio" -Captions.CurrentSystemLanguage="Idioma Atual do Sistema (%1)" +Captions="Legendas (experimental)" +Captions.AudioSource="Fonte de áudio" +Captions.CurrentSystemLanguage="Idioma atual do sistema (%1)" Captions.Provider="Provedor" Captions.Error.GenericFail="Falha ao iniciar legendas" @@ -27,22 +27,22 @@ OutputTimer.Record.EnableEverytime="Ativar o timer de gravação o tempo todo" OutputTimer.Record.PauseTimer="Pausar o temporizador quando a gravação é pausada" Scripts="Scripts" -LoadedScripts="Scripts Carregados" -AddScripts="Adicionar Scripts" -RemoveScripts="Remover Scripts" -ReloadScripts="Recarregar Scripts" +LoadedScripts="Scripts carregados" +AddScripts="Adicionar scripts" +RemoveScripts="Remover scripts" +ReloadScripts="Recarregar scripts" Reload="Recarregar" OpenFileLocation="Abrir local do arquivo" -PythonSettings="Configurações Python" -PythonSettings.PythonInstallPath32bit="Caminho de Instalação Python (32 bits)" -PythonSettings.PythonInstallPath64bit="Caminho de Instalação Python (64 bits)" -PythonSettings.BrowsePythonPath="Procurar Caminho do Python" -ScriptLogWindow="Log dos Scripts" +PythonSettings="Configurações do Python" +PythonSettings.PythonInstallPath32bit="Caminho de instalação do Python (32 bits)" +PythonSettings.PythonInstallPath64bit="Caminho de instalação do Python (64 bits)" +PythonSettings.BrowsePythonPath="Procurar caminho do Python" +ScriptLogWindow="Log de scripts" Description="Descrição" ScriptDescriptionLink.Text="Abrir este link no seu navegador padrão?" ScriptDescriptionLink.Text.Url="URL: %1" ScriptDescriptionLink.OpenURL="Abrir URL" -FileFilter.ScriptFiles="Arquivos de Scripts" -FileFilter.AllFiles="Todos os Arquivos" +FileFilter.ScriptFiles="Arquivos de scripts" +FileFilter.AllFiles="Todos os arquivos" diff --git a/UI/frontend-plugins/frontend-tools/data/locale/pt-PT.ini b/UI/frontend-plugins/frontend-tools/data/locale/pt-PT.ini index 6b15cc7..08f411a 100644 --- a/UI/frontend-plugins/frontend-tools/data/locale/pt-PT.ini +++ b/UI/frontend-plugins/frontend-tools/data/locale/pt-PT.ini @@ -31,12 +31,15 @@ LoadedScripts="Scripts Carregados" AddScripts="Adicionar Scripts" RemoveScripts="Remover Scripts" ReloadScripts="Recarregar Scripts" +Reload="Recarregar" +OpenFileLocation="Abrir local do ficheiro" PythonSettings="Definições do Python" PythonSettings.PythonInstallPath32bit="Caminho da Instalação do Python (32bits)" PythonSettings.PythonInstallPath64bit="Caminho da Instalação do Python (64bits)" PythonSettings.BrowsePythonPath="Procurar o Caminho Python" ScriptLogWindow="Log do Script" Description="Descrição" +ScriptDescriptionLink.Text="Abrir este link no teu navegador padrão?" ScriptDescriptionLink.Text.Url="URL: %1" ScriptDescriptionLink.OpenURL="Abrir URL" diff --git a/UI/frontend-plugins/frontend-tools/data/locale/ro-RO.ini b/UI/frontend-plugins/frontend-tools/data/locale/ro-RO.ini index 9182860..dbb254b 100644 --- a/UI/frontend-plugins/frontend-tools/data/locale/ro-RO.ini +++ b/UI/frontend-plugins/frontend-tools/data/locale/ro-RO.ini @@ -5,7 +5,7 @@ SceneSwitcher.OnNoMatch.SwitchTo="Schimbă la:" SceneSwitcher.CheckInterval="Verifică titlul ferestrei active la fiecare:" SceneSwitcher.ActiveOrNotActive="Schimbătorul de scene este:" InvalidRegex.Title="Expresie regulată invalidă" -InvalidRegex.Text="Expresia obișnuită pe care ați introdus-o este invalidă." +InvalidRegex.Text="Expresia regulată pe care ai introdus-o este nevalidă." Active="Activ" Inactive="Inactiv" Start="Pornește" @@ -39,10 +39,10 @@ PythonSettings.PythonInstallPath64bit="Calea instalării Python (64bit)" PythonSettings.BrowsePythonPath="Răsfoiește calea Python" ScriptLogWindow="Jurnalul scripturilor" Description="Descriere" -ScriptDescriptionLink.Text="Deschideți acest link în browser-ul web implicit?" +ScriptDescriptionLink.Text="Deschizi acest link în browserul web implicit?" ScriptDescriptionLink.Text.Url="URL: %1" ScriptDescriptionLink.OpenURL="Deschide URL-ul" -FileFilter.ScriptFiles="Fișiere Script" +FileFilter.ScriptFiles="Fișiere de script" FileFilter.AllFiles="Toate fișierele" diff --git a/UI/frontend-plugins/frontend-tools/data/locale/sl-SI.ini b/UI/frontend-plugins/frontend-tools/data/locale/sl-SI.ini index f164b39..32e141d 100644 --- a/UI/frontend-plugins/frontend-tools/data/locale/sl-SI.ini +++ b/UI/frontend-plugins/frontend-tools/data/locale/sl-SI.ini @@ -31,6 +31,8 @@ LoadedScripts="Naloženi skripti" AddScripts="Dodaj skripte" RemoveScripts="Odstrani skripte" ReloadScripts="Ponovno naloži skripte" +Reload="Ponovno naloži" +OpenFileLocation="Odpri lokacijo datoteke" PythonSettings="Nastavitve Python" PythonSettings.PythonInstallPath32bit="Namestitvena pot Pythona (32-bitni)" PythonSettings.PythonInstallPath64bit="Namestitvena pot Pythona (64-bitni)" diff --git a/UI/frontend-plugins/frontend-tools/data/locale/sv-SE.ini b/UI/frontend-plugins/frontend-tools/data/locale/sv-SE.ini index f5ae4ab..e3233e6 100644 --- a/UI/frontend-plugins/frontend-tools/data/locale/sv-SE.ini +++ b/UI/frontend-plugins/frontend-tools/data/locale/sv-SE.ini @@ -2,7 +2,7 @@ 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.CheckInterval="Kontrollera titel på aktivt fönster varje:" SceneSwitcher.ActiveOrNotActive="Scenbytaren är:" InvalidRegex.Title="Ogiltigt reguljärt uttryck" InvalidRegex.Text="Det reguljära uttrycket du angav är ogiltigt." @@ -18,9 +18,9 @@ Captions.Provider="Tillhandahållare" Captions.Error.GenericFail="Det gick inte att starta undertexter" OutputTimer="Utdatatimer" -OutputTimer.Stream="Sluta streama efter:" +OutputTimer.Stream="Stoppa strömmen efter:" OutputTimer.Record="Stoppa inspelningen efter:" -OutputTimer.Stream.StoppingIn="Streamen stoppas om:" +OutputTimer.Stream.StoppingIn="Strömmen stoppas om:" OutputTimer.Record.StoppingIn="Inspelningen stoppas om:" OutputTimer.Stream.EnableEverytime="Aktivera strömtimer varje gång" OutputTimer.Record.EnableEverytime="Aktivera inspelningstimer varje gång" diff --git a/UI/frontend-plugins/frontend-tools/data/locale/vi-VN.ini b/UI/frontend-plugins/frontend-tools/data/locale/vi-VN.ini index 6b0c67c..89efb5e 100644 --- a/UI/frontend-plugins/frontend-tools/data/locale/vi-VN.ini +++ b/UI/frontend-plugins/frontend-tools/data/locale/vi-VN.ini @@ -24,18 +24,24 @@ OutputTimer.Stream.StoppingIn="Stream sẽ dừng trong:" OutputTimer.Record.StoppingIn="Quay video sẽ dừng trong:" OutputTimer.Stream.EnableEverytime="Bật hẹn giờ phát luồng mỗi lần" OutputTimer.Record.EnableEverytime="Bật hẹn giờ phát mỗi lần" +OutputTimer.Record.PauseTimer="Dừng bấm giờ khi ghi hình tạm dừng" Scripts="Kịch bản" LoadedScripts="Kịch bản đã nạp" AddScripts="Thêm script" RemoveScripts="Gỡ bỏ kịch bản" ReloadScripts="Nạp lại kịch bản" +Reload="Tải lại" +OpenFileLocation="Mở vị trí tệp" PythonSettings="Thiết đặt Python" PythonSettings.PythonInstallPath32bit="Đường dẫn cài đặt Python (32bit)" PythonSettings.PythonInstallPath64bit="Đường dẫn cài đặt Python (64bit)" PythonSettings.BrowsePythonPath="Duyệt đường dẫn Python" ScriptLogWindow="Bản ghi kịch bản" Description="Mô tả" +ScriptDescriptionLink.Text="Mở liên kết trên trình duyệt web mặc định?" +ScriptDescriptionLink.Text.Url="URL: %1" +ScriptDescriptionLink.OpenURL="Mở URL" FileFilter.ScriptFiles="Tập tin script" FileFilter.AllFiles="Tất cả tập tin" diff --git a/UI/frontend-plugins/frontend-tools/frontend-tools-config.h.in b/UI/frontend-plugins/frontend-tools/frontend-tools-config.h.in index 8bc3af9..c2e45d9 100644 --- a/UI/frontend-plugins/frontend-tools/frontend-tools-config.h.in +++ b/UI/frontend-plugins/frontend-tools/frontend-tools-config.h.in @@ -16,7 +16,6 @@ #define OFF 0 #endif -#define BUILD_CAPTIONS @BUILD_CAPTIONS@ #define ENABLE_SCRIPTING @SCRIPTING_ENABLED@ #define COMPILE_LUA @COMPILE_LUA@ #define COMPILE_PYTHON @COMPILE_PYTHON@ diff --git a/UI/frontend-plugins/frontend-tools/frontend-tools.c b/UI/frontend-plugins/frontend-tools/frontend-tools.c index 78e199d..2b9cb81 100644 --- a/UI/frontend-plugins/frontend-tools/frontend-tools.c +++ b/UI/frontend-plugins/frontend-tools/frontend-tools.c @@ -7,7 +7,7 @@ OBS_MODULE_USE_DEFAULT_LOCALE("frontend-tools", "en-US") void InitSceneSwitcher(); void FreeSceneSwitcher(); -#if defined(_WIN32) && BUILD_CAPTIONS +#if defined(_WIN32) void InitCaptions(); void FreeCaptions(); #endif @@ -22,7 +22,7 @@ void FreeScripts(); bool obs_module_load(void) { -#if defined(_WIN32) && BUILD_CAPTIONS +#if defined(_WIN32) InitCaptions(); #endif InitSceneSwitcher(); @@ -35,7 +35,7 @@ bool obs_module_load(void) void obs_module_unload(void) { -#if defined(_WIN32) && BUILD_CAPTIONS +#if defined(_WIN32) FreeCaptions(); #endif FreeSceneSwitcher(); diff --git a/UI/hotkey-edit.cpp b/UI/hotkey-edit.cpp index 37e5a7d..d2846f9 100644 --- a/UI/hotkey-edit.cpp +++ b/UI/hotkey-edit.cpp @@ -101,7 +101,7 @@ void OBSHotkeyEdit::mousePressEvent(QMouseEvent *event) case Qt::MouseButtonMask: return; - case Qt::MidButton: + case Qt::MiddleButton: new_key.key = OBS_KEY_MOUSE3; break; @@ -293,11 +293,13 @@ void OBSHotkeyWidget::AddEdit(obs_key_combination combo, int idx) auto add = new QPushButton; add->setProperty("themeID", "addIconSmall"); + add->setToolTip(QTStr("Add")); add->setFixedSize(24, 24); add->setFlat(true); auto remove = new QPushButton; remove->setProperty("themeID", "removeIconSmall"); + remove->setToolTip(QTStr("Remove")); remove->setEnabled(removeButtons.size() > 0); remove->setFixedSize(24, 24); remove->setFlat(true); diff --git a/UI/installer/mp-installer.nsi b/UI/installer/mp-installer.nsi index 56006b4..b71db4a 100644 --- a/UI/installer/mp-installer.nsi +++ b/UI/installer/mp-installer.nsi @@ -104,35 +104,34 @@ Function PreReqCheck ${EndIf} !ifdef INSTALL64 - ; 64 bit Visual Studio 2017 runtime check + ; 64 bit Visual Studio 2019 runtime check ClearErrors - SetOutPath "$TEMP\OBS" - File check_for_64bit_visual_studio_2017_runtimes.exe - ExecWait "$TEMP\OBS\check_for_64bit_visual_studio_2017_runtimes.exe" $R0 - Delete "$TEMP\OBS\check_for_64bit_visual_studio_2017_runtimes.exe" - RMDir "$TEMP\OBS" - IntCmp $R0 126 vs2017Missing_64 vs2017OK_64 - vs2017Missing_64: - MessageBox MB_YESNO|MB_ICONEXCLAMATION "Your system is missing runtime components that ${APPNAME} requires. Would you like to download them?" IDYES vs2017true_64 IDNO vs2017false_64 - vs2017true_64: - ExecShell "open" "https://obsproject.com/visual-studio-2017-runtimes-64-bit" - vs2017false_64: + SetOutPath "$PLUGINSDIR" + File check_for_64bit_visual_studio_2019_runtimes.exe + ExecWait "$PLUGINSDIR\check_for_64bit_visual_studio_2019_runtimes.exe" $R0 + Delete "$PLUGINSDIR\check_for_64bit_visual_studio_2019_runtimes.exe" + IntCmp $R0 126 vs2019Missing_64 vs2019OK_64 + vs2019Missing_64: + MessageBox MB_YESNO|MB_ICONEXCLAMATION "Your system is missing runtime components that ${APPNAME} requires. Would you like to download them?" IDYES vs2019true_64 IDNO vs2019false_64 + vs2019true_64: + ExecShell "open" "https://obsproject.com/visual-studio-2019-runtimes-64-bit" + vs2019false_64: Quit - vs2017OK_64: + vs2019OK_64: ClearErrors !else - ; 32 bit Visual Studio 2017 runtime check + ; 32 bit Visual Studio 2019 runtime check ClearErrors GetDLLVersion "vcruntime140.DLL" $R0 $R1 GetDLLVersion "msvcp140.DLL" $R0 $R1 - IfErrors vs2017Missing_32 vs2017OK_32 - vs2017Missing_32: - MessageBox MB_YESNO|MB_ICONEXCLAMATION "Your system is missing runtime components that ${APPNAME} requires. Would you like to download them?" IDYES vs2017true_32 IDNO vs2017false_32 - vs2017true_32: - ExecShell "open" "https://obsproject.com/visual-studio-2017-runtimes-32-bit" - vs2017false_32: + IfErrors vs2019Missing_32 vs2019OK_32 + vs2019Missing_32: + MessageBox MB_YESNO|MB_ICONEXCLAMATION "Your system is missing runtime components that ${APPNAME} requires. Would you like to download them?" IDYES vs2019true_32 IDNO vs2019false_32 + vs2019true_32: + ExecShell "open" "https://obsproject.com/visual-studio-2019-runtimes-32-bit" + vs2019false_32: Quit - vs2017OK_32: + vs2019OK_32: ClearErrors !endif diff --git a/UI/obs-app.cpp b/UI/obs-app.cpp index 15b370a..afe2e2e 100644 --- a/UI/obs-app.cpp +++ b/UI/obs-app.cpp @@ -35,10 +35,12 @@ #include #include #include +#include #include "qt-wrappers.hpp" #include "obs-app.hpp" #include "log-viewer.hpp" +#include "slider-ignorewheel.hpp" #include "window-basic-main.hpp" #include "window-basic-settings.hpp" #include "crash-report.hpp" @@ -114,7 +116,7 @@ QObject *CreateShortcutFilter() case Qt::MouseButtonMask: return false; - case Qt::MidButton: + case Qt::MiddleButton: hotkey.key = OBS_KEY_MOUSE3; break; @@ -446,6 +448,8 @@ bool OBSApp::InitGlobalConfigDefaults() true); config_set_default_bool(globalConfig, "BasicWindow", "ShowSourceIcons", true); + config_set_default_bool(globalConfig, "BasicWindow", + "ShowContextToolbars", true); config_set_default_bool(globalConfig, "BasicWindow", "StudioModeLabels", true); @@ -1125,7 +1129,12 @@ OBSApp::OBSApp(int &argc, char **argv, profiler_name_store_t *store) { sleepInhibitor = os_inhibit_sleep_create("OBS Video/audio"); +#ifdef __APPLE__ + setWindowIcon( + QIcon::fromTheme("obs", QIcon(":/res/images/obs_256x256.png"))); +#else setWindowIcon(QIcon::fromTheme("obs", QIcon(":/res/images/obs.png"))); +#endif } OBSApp::~OBSApp() @@ -1257,6 +1266,8 @@ void OBSApp::AppInit() Str("Untitled")); config_set_default_string(globalConfig, "Basic", "SceneCollectionFile", Str("Untitled")); + config_set_default_bool(globalConfig, "Basic", "ConfigOnNewProfile", + true); if (!config_has_user_value(globalConfig, "Basic", "Profile")) { config_set_string(globalConfig, "Basic", "Profile", @@ -1433,6 +1444,8 @@ string OBSApp::GetVersionString() const ver << "windows)"; #elif __APPLE__ ver << "mac)"; +#elif __OpenBSD__ + ver << "openbsd)"; #elif __FreeBSD__ ver << "freebsd)"; #else /* assume linux for the time being */ @@ -1890,6 +1903,17 @@ static auto ProfilerFree = [](void *) { profiler_free(); }; +QAccessibleInterface *accessibleFactory(const QString &classname, + QObject *object) +{ + if (classname == QLatin1String("VolumeSlider") && object && + object->isWidgetType()) + return new VolumeAccessibleInterface( + static_cast(object)); + + return nullptr; +} + static const char *run_program_init = "run_program_init"; static int run_program(fstream &logFile, int argc, char *argv[]) { @@ -1908,6 +1932,10 @@ static int run_program(fstream &logFile, int argc, char *argv[]) #if (QT_VERSION >= QT_VERSION_CHECK(5, 11, 0)) QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling); #endif +#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)) + QGuiApplication::setHighDpiScaleFactorRoundingPolicy( + Qt::HighDpiScaleFactorRoundingPolicy::PassThrough); +#endif #if !defined(_WIN32) && !defined(__APPLE__) && BROWSER_AVAILABLE setenv("QT_NO_GLIB", "1", true); @@ -1921,6 +1949,8 @@ static int run_program(fstream &logFile, int argc, char *argv[]) OBSApp program(argc, argv, profilerNameStore.get()); try { + QAccessible::installFactory(accessibleFactory); + bool created_log = false; program.AppInit(); @@ -1929,13 +1959,21 @@ static int run_program(fstream &logFile, int argc, char *argv[]) OBSTranslator translator; program.installTranslator(&translator); -#ifdef _WIN32 /* --------------------------------------- */ /* check and warn if already running */ bool cancel_launch = false; bool already_running = false; + +#if defined(_WIN32) RunOnceMutex rom = GetRunOnceMutex(already_running); +#elif defined(__APPLE__) + CheckAppWithSameBundleID(already_running); +#elif defined(__linux__) + RunningInstanceCheck(already_running); +#elif defined(__FreeBSD__) || defined(__DragonFly__) + PIDFileCheck(already_running); +#endif if (!already_running) { goto run; @@ -1979,7 +2017,6 @@ static int run_program(fstream &logFile, int argc, char *argv[]) /* --------------------------------------- */ run: -#endif #if !defined(_WIN32) && !defined(__APPLE__) && !defined(__FreeBSD__) // Mounted by termina during chromeOS linux container startup diff --git a/UI/obs-frontend-api/obs-frontend-api.h b/UI/obs-frontend-api/obs-frontend-api.h index 83dd9c7..bee32ee 100644 --- a/UI/obs-frontend-api/obs-frontend-api.h +++ b/UI/obs-frontend-api/obs-frontend-api.h @@ -49,6 +49,7 @@ enum obs_frontend_event { OBS_FRONTEND_EVENT_RECORDING_UNPAUSED, OBS_FRONTEND_EVENT_TRANSITION_DURATION_CHANGED, + OBS_FRONTEND_EVENT_REPLAY_BUFFER_SAVED, }; /* ------------------------------------------------------------------------- */ diff --git a/UI/platform-osx.mm b/UI/platform-osx.mm index 228e38f..c558c7a 100644 --- a/UI/platform-osx.mm +++ b/UI/platform-osx.mm @@ -87,6 +87,29 @@ bool InitApplicationBundle() #endif } +void CheckAppWithSameBundleID(bool &already_running) +{ + try { + NSBundle *bundle = [NSBundle mainBundle]; + if (!bundle) + throw "Could not find main bundle"; + + NSString *bundleID = [bundle bundleIdentifier]; + if (!bundleID) + throw "Could not find bundle identifier"; + + int app_count = + [NSRunningApplication + runningApplicationsWithBundleIdentifier:bundleID] + .count; + + already_running = app_count > 1; + + } catch (const char *error) { + blog(LOG_ERROR, "CheckAppWithSameBundleID: %s", error); + } +} + string GetDefaultVideoSavePath() { NSFileManager *fm = [NSFileManager defaultManager]; diff --git a/UI/platform-x11.cpp b/UI/platform-x11.cpp index 13af10e..cb27172 100644 --- a/UI/platform-x11.cpp +++ b/UI/platform-x11.cpp @@ -27,8 +27,151 @@ #include #include "platform.hpp" + +#ifdef __linux__ +#include +#include +#include +#include +#include +#endif +#if defined(__FreeBSD__) || defined(__DragonFly__) +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#endif + using namespace std; +#ifdef __linux__ +void RunningInstanceCheck(bool &already_running) +{ + int uniq = socket(AF_LOCAL, SOCK_DGRAM | SOCK_CLOEXEC, 0); + + if (uniq == -1) { + blog(LOG_ERROR, + "Failed to check for running instance, socket: %d", errno); + already_running = 0; + return; + } + + struct sockaddr_un bindInfo; + memset(&bindInfo, 0, sizeof(sockaddr_un)); + bindInfo.sun_family = AF_LOCAL; + char *abstactSockName = NULL; + asprintf(&abstactSockName, "%s %d %s", "/com/obsproject", getpid(), + App()->GetVersionString().c_str()); + memmove(bindInfo.sun_path + 1, abstactSockName, + strlen(abstactSockName)); + free(abstactSockName); + + int bindErr = bind(uniq, (struct sockaddr *)&bindInfo, + sizeof(struct sockaddr_un)); + already_running = bindErr == 0 ? 0 : 1; + + if (already_running) { + return; + } + + FILE *fp = fopen("/proc/net/unix", "re"); + + if (fp == NULL) { + return; + } + + char *line = NULL; + size_t n = 0; + int obsCnt = 0; + while (getdelim(&line, &n, ' ', fp) != EOF) { + line[strcspn(line, "\n")] = '\0'; + if (*line == '@') { + if (strstr(line, "@/com/obsproject") != NULL) { + ++obsCnt; + } + } + } + already_running = obsCnt == 1 ? 0 : 1; + free(line); + fclose(fp); +} +#endif +#if defined(__FreeBSD__) || defined(__DragonFly__) +struct RunOnce { + std::thread thr; + static const char *thr_name; + std::condition_variable cv; + std::condition_variable wait_cv; + std::mutex mtx; + bool exiting = false; + bool name_changed = false; + + void thr_proc() + { + std::unique_lock lk(mtx); + pthread_set_name_np(pthread_self(), thr_name); + name_changed = true; + wait_cv.notify_all(); + cv.wait(lk, [this]() { return exiting; }); + } + + ~RunOnce() + { + if (thr.joinable()) { + std::unique_lock lk(mtx); + exiting = true; + cv.notify_one(); + lk.unlock(); + thr.join(); + } + } +} RO; +const char *RunOnce::thr_name = "OBS runonce"; + +void PIDFileCheck(bool &already_running) +{ + std::string tmpfile_name = + "/tmp/obs-studio.lock." + to_string(geteuid()); + int fd = open(tmpfile_name.c_str(), O_RDWR | O_CREAT | O_EXLOCK, 0600); + if (fd == -1) { + already_running = true; + return; + } + + already_running = false; + + procstat *ps = procstat_open_sysctl(); + unsigned int count; + auto procs = procstat_getprocs(ps, KERN_PROC_UID | KERN_PROC_INC_THREAD, + geteuid(), &count); + for (unsigned int i = 0; i < count; i++) { + if (!strncmp(procs[i].ki_tdname, RunOnce::thr_name, + sizeof(procs[i].ki_tdname))) { + already_running = true; + break; + } + } + procstat_freeprocs(ps, procs); + procstat_close(ps); + + RO.thr = std::thread(std::mem_fn(&RunOnce::thr_proc), &RO); + + { + std::unique_lock lk(RO.mtx); + RO.wait_cv.wait(lk, []() { return RO.name_changed; }); + } + + unlink(tmpfile_name.c_str()); + close(fd); +} +#endif + static inline bool check_path(const char *data, const char *path, string &output) { diff --git a/UI/platform.hpp b/UI/platform.hpp index df21818..7e7d47e 100644 --- a/UI/platform.hpp +++ b/UI/platform.hpp @@ -68,4 +68,11 @@ void EnableOSXVSync(bool enable); void EnableOSXDockIcon(bool enable); void InstallNSApplicationSubclass(); void disableColorSpaceConversion(QWidget *window); +void CheckAppWithSameBundleID(bool &already_running); +#endif +#ifdef __linux__ +void RunningInstanceCheck(bool &already_running); +#endif +#if defined(__FreeBSD__) || defined(__DragonFly__) +void PIDFileCheck(bool &already_running); #endif diff --git a/UI/properties-view.cpp b/UI/properties-view.cpp index 849dd48..7dab866 100644 --- a/UI/properties-view.cpp +++ b/UI/properties-view.cpp @@ -329,8 +329,7 @@ void OBSPropertiesView::AddInt(obs_property_t *prop, QFormLayout *layout, int val = (int)obs_data_get_int(settings, name); QSpinBox *spin = new SpinBoxIgnoreScroll(); - if (!obs_property_enabled(prop)) - spin->setEnabled(false); + spin->setEnabled(obs_property_enabled(prop)); int minVal = obs_property_int_min(prop); int maxVal = obs_property_int_max(prop); @@ -354,6 +353,7 @@ void OBSPropertiesView::AddInt(obs_property_t *prop, QFormLayout *layout, slider->setPageStep(stepVal); slider->setValue(val); slider->setOrientation(Qt::Horizontal); + slider->setEnabled(obs_property_enabled(prop)); subLayout->addWidget(slider); connect(slider, SIGNAL(valueChanged(int)), spin, diff --git a/UI/qt-wrappers.cpp b/UI/qt-wrappers.cpp index b9d00a7..76c5320 100644 --- a/UI/qt-wrappers.cpp +++ b/UI/qt-wrappers.cpp @@ -22,10 +22,12 @@ #include #include #include +#include #include #include #include #include +#include #if !defined(_WIN32) && !defined(__APPLE__) #include @@ -326,6 +328,15 @@ bool LineEditChanged(QEvent *event) return false; } +void SetComboItemEnabled(QComboBox *c, int idx, bool enabled) +{ + QStandardItemModel *model = + dynamic_cast(c->model()); + QStandardItem *item = model->item(idx); + item->setFlags(enabled ? Qt::ItemIsSelectable | Qt::ItemIsEnabled + : Qt::NoItemFlags); +} + void setThemeID(QWidget *widget, const QString &themeID) { if (widget->property("themeID").toString() != themeID) { diff --git a/UI/qt-wrappers.hpp b/UI/qt-wrappers.hpp index 71b1135..600bab2 100644 --- a/UI/qt-wrappers.hpp +++ b/UI/qt-wrappers.hpp @@ -31,6 +31,7 @@ #define QT_TO_UTF8(str) str.toUtf8().constData() class QDataStream; +class QComboBox; class QWidget; class QLayout; class QString; @@ -106,6 +107,8 @@ static inline Qt::ConnectionType WaitConnection() bool LineEditCanceled(QEvent *event); bool LineEditChanged(QEvent *event); +void SetComboItemEnabled(QComboBox *c, int idx, bool enabled); + void setThemeID(QWidget *widget, const QString &themeID); QString SelectDirectory(QWidget *parent, QString title, QString path); diff --git a/UI/slider-absoluteset-style.cpp b/UI/slider-absoluteset-style.cpp index 3417604..79fd14e 100644 --- a/UI/slider-absoluteset-style.cpp +++ b/UI/slider-absoluteset-style.cpp @@ -15,6 +15,6 @@ int SliderAbsoluteSetStyle::styleHint(QStyle::StyleHint hint, QStyleHintReturn *returnData = 0) const { if (hint == QStyle::SH_Slider_AbsoluteSetButtons) - return (Qt::LeftButton | Qt::MidButton); + return (Qt::LeftButton | Qt::MiddleButton); return QProxyStyle::styleHint(hint, option, widget, returnData); } diff --git a/UI/slider-ignorewheel.cpp b/UI/slider-ignorewheel.cpp index 8203c81..11023d6 100644 --- a/UI/slider-ignorewheel.cpp +++ b/UI/slider-ignorewheel.cpp @@ -1,4 +1,5 @@ #include "slider-ignorewheel.hpp" +#include "volume-control.hpp" SliderIgnoreScroll::SliderIgnoreScroll(QWidget *parent) : QSlider(parent) { @@ -20,3 +21,77 @@ void SliderIgnoreScroll::wheelEvent(QWheelEvent *event) else QSlider::wheelEvent(event); } + +VolumeSlider::VolumeSlider(obs_fader_t *fader, QWidget *parent) + : SliderIgnoreScroll(parent) +{ + fad = fader; +} + +VolumeSlider::VolumeSlider(obs_fader_t *fader, Qt::Orientation orientation, + QWidget *parent) + : SliderIgnoreScroll(orientation, parent) +{ + fad = fader; +} + +VolumeAccessibleInterface::VolumeAccessibleInterface(QWidget *w) + : QAccessibleWidget(w) +{ +} + +VolumeSlider *VolumeAccessibleInterface::slider() const +{ + return qobject_cast(object()); +} + +QString VolumeAccessibleInterface::text(QAccessible::Text t) const +{ + if (slider()->isVisible()) { + switch (t) { + case QAccessible::Text::Value: + return currentValue().toString(); + default: + break; + } + } + return QAccessibleWidget::text(t); +} + +QVariant VolumeAccessibleInterface::currentValue() const +{ + QString text; + float db = obs_fader_get_db(slider()->fad); + + if (db < -96.0f) + text = "-inf dB"; + else + text = QString::number(db, 'f', 1).append(" dB"); + + return text; +} + +void VolumeAccessibleInterface::setCurrentValue(const QVariant &value) +{ + slider()->setValue(value.toInt()); +} + +QVariant VolumeAccessibleInterface::maximumValue() const +{ + return slider()->maximum(); +} + +QVariant VolumeAccessibleInterface::minimumValue() const +{ + return slider()->minimum(); +} + +QVariant VolumeAccessibleInterface::minimumStepSize() const +{ + return slider()->singleStep(); +} + +QAccessible::Role VolumeAccessibleInterface::role() const +{ + return QAccessible::Role::Slider; +} diff --git a/UI/slider-ignorewheel.hpp b/UI/slider-ignorewheel.hpp index f5c7e5d..40d0448 100644 --- a/UI/slider-ignorewheel.hpp +++ b/UI/slider-ignorewheel.hpp @@ -1,8 +1,10 @@ #pragma once +#include "obs.hpp" #include #include #include +#include class SliderIgnoreScroll : public QSlider { Q_OBJECT @@ -15,3 +17,35 @@ public: protected: virtual void wheelEvent(QWheelEvent *event) override; }; + +class VolumeSlider : public SliderIgnoreScroll { + Q_OBJECT + +public: + obs_fader_t *fad; + + VolumeSlider(obs_fader_t *fader, QWidget *parent = nullptr); + VolumeSlider(obs_fader_t *fader, Qt::Orientation orientation, + QWidget *parent = nullptr); +}; + +class VolumeAccessibleInterface : public QAccessibleWidget { + +public: + VolumeAccessibleInterface(QWidget *w); + + QVariant currentValue() const; + void setCurrentValue(const QVariant &value); + + QVariant maximumValue() const; + QVariant minimumValue() const; + + QVariant minimumStepSize() const; + +private: + VolumeSlider *slider() const; + +protected: + virtual QAccessible::Role role() const override; + virtual QString text(QAccessible::Text t) const override; +}; diff --git a/UI/source-tree.cpp b/UI/source-tree.cpp index d234778..46f5c24 100644 --- a/UI/source-tree.cpp +++ b/UI/source-tree.cpp @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -84,12 +85,18 @@ SourceTreeItem::SourceTreeItem(SourceTree *tree_, OBSSceneItem sceneitem_) vis->setFixedSize(16, 16); vis->setChecked(obs_sceneitem_visible(sceneitem)); vis->setStyleSheet("background: none"); + vis->setAccessibleName(QTStr("Basic.Main.Sources.Visibility")); + vis->setAccessibleDescription( + QTStr("Basic.Main.Sources.VisibilityDescription").arg(name)); lock = new LockedCheckBox(); lock->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum); lock->setFixedSize(16, 16); lock->setChecked(obs_sceneitem_locked(sceneitem)); lock->setStyleSheet("background: none"); + lock->setAccessibleName(QTStr("Basic.Main.Sources.Lock")); + lock->setAccessibleDescription( + QTStr("Basic.Main.Sources.LockDescription").arg(name)); label = new QLabel(QT_UTF8(name)); label->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); @@ -354,6 +361,7 @@ void SourceTreeItem::ExitEditMode(bool save) editor = nullptr; setFocusPolicy(Qt::NoFocus); boxLayout->insertWidget(index, label); + label->setFocus(); /* ----------------------------------------- */ /* check for empty string */ @@ -528,13 +536,13 @@ void SourceTreeItem::ExpandClicked(bool checked) void SourceTreeItem::Select() { tree->SelectItem(sceneitem, true); - OBSBasic::Get()->UpdateContextBar(); + OBSBasic::Get()->UpdateContextBarDeferred(); } void SourceTreeItem::Deselect() { tree->SelectItem(sceneitem, false); - OBSBasic::Get()->UpdateContextBar(); + OBSBasic::Get()->UpdateContextBarDeferred(); } /* ========================================================================= */ diff --git a/UI/volume-control.cpp b/UI/volume-control.cpp index 7543d15..cfc64b6 100644 --- a/UI/volume-control.cpp +++ b/UI/volume-control.cpp @@ -89,7 +89,7 @@ void VolControl::updateText() : "VolControl.SliderUnmuted"; QString sourceName = obs_source_get_name(source); - QString accText = QTStr(accTextLookup).arg(sourceName, db); + QString accText = QTStr(accTextLookup).arg(sourceName); slider->setAccessibleName(accText); } @@ -161,7 +161,7 @@ VolControl::VolControl(OBSSource source_, bool showConfig, bool vertical) QHBoxLayout *meterLayout = new QHBoxLayout; volMeter = new VolumeMeter(nullptr, obs_volmeter, true); - slider = new SliderIgnoreScroll(Qt::Vertical); + slider = new VolumeSlider(obs_fader, Qt::Vertical); nameLayout->setAlignment(Qt::AlignCenter); meterLayout->setAlignment(Qt::AlignCenter); @@ -205,7 +205,7 @@ VolControl::VolControl(OBSSource source_, bool showConfig, bool vertical) QHBoxLayout *botLayout = new QHBoxLayout; volMeter = new VolumeMeter(nullptr, obs_volmeter, false); - slider = new SliderIgnoreScroll(Qt::Horizontal); + slider = new VolumeSlider(obs_fader, Qt::Horizontal); textLayout->setContentsMargins(0, 0, 0, 0); textLayout->addWidget(nameLabel); diff --git a/UI/win-update/updater/CMakeLists.txt b/UI/win-update/updater/CMakeLists.txt index 83309c3..dcf43f6 100644 --- a/UI/win-update/updater/CMakeLists.txt +++ b/UI/win-update/updater/CMakeLists.txt @@ -9,17 +9,19 @@ endif() project(updater) -include_directories(${OBS_JANSSON_INCLUDE_DIRS}) include_directories(${LIBLZMA_INCLUDE_DIRS}) +include_directories(SYSTEM "${CMAKE_SOURCE_DIR}/deps/json11") include_directories(SYSTEM "${CMAKE_SOURCE_DIR}/libobs") include_directories(${BLAKE2_INCLUDE_DIR}) set(updater_HEADERS + ${CMAKE_SOURCE_DIR}/deps/json11/json11.hpp ../win-update-helpers.hpp resource.h updater.hpp ) set(updater_SOURCES + ${CMAKE_SOURCE_DIR}/deps/json11/json11.cpp ../win-update-helpers.cpp init-hook-files.c updater.cpp @@ -40,7 +42,6 @@ add_executable(updater WIN32 ${updater_SOURCES} ) target_link_libraries(updater - ${OBS_JANSSON_IMPORT} ${STATIC_ZLIB_PATH} lzma blake2 diff --git a/UI/win-update/updater/updater.cpp b/UI/win-update/updater/updater.cpp index 9a603a4..53739c4 100644 --- a/UI/win-update/updater/updater.cpp +++ b/UI/win-update/updater/updater.cpp @@ -26,6 +26,7 @@ #include using namespace std; +using namespace json11; /* ----------------------------------------------------------------------- */ @@ -59,7 +60,7 @@ void FreeWinHttpHandle(HINTERNET handle) static inline bool is_64bit_windows(void); -static inline bool HasVS2017Redist2() +static inline bool HasVS2019Redist2() { wchar_t base[MAX_PATH]; wchar_t path[MAX_PATH]; @@ -70,32 +71,34 @@ static inline bool HasVS2017Redist2() SHGetFolderPathW(NULL, folder, NULL, SHGFP_TYPE_CURRENT, base); - StringCbCopyW(path, sizeof(path), base); - StringCbCatW(path, sizeof(path), L"\\msvcp140.dll"); - handle = FindFirstFileW(path, &wfd); - if (handle == INVALID_HANDLE_VALUE) { - return false; - } else { - FindClose(handle); +#define check_dll_installed(dll) \ + do { \ + StringCbCopyW(path, sizeof(path), base); \ + StringCbCatW(path, sizeof(path), L"\\" dll ".dll"); \ + handle = FindFirstFileW(path, &wfd); \ + if (handle == INVALID_HANDLE_VALUE) { \ + return false; \ + } else { \ + FindClose(handle); \ + } \ + } while (false) + + check_dll_installed(L"msvcp140"); + check_dll_installed(L"vcruntime140"); + if (!is32bit) { + check_dll_installed(L"vcruntime140_1"); } - StringCbCopyW(path, sizeof(path), base); - StringCbCatW(path, sizeof(path), L"\\vcruntime140.dll"); - handle = FindFirstFileW(path, &wfd); - if (handle == INVALID_HANDLE_VALUE) { - return false; - } else { - FindClose(handle); - } +#undef check_dll_installed return true; } -static bool HasVS2017Redist() +static bool HasVS2019Redist() { PVOID old = nullptr; bool redirect = !!Wow64DisableWow64FsRedirection(&old); - bool success = HasVS2017Redist2(); + bool success = HasVS2019Redist2(); if (redirect) Wow64RevertWow64FsRedirection(old); return success; @@ -603,68 +606,63 @@ static inline bool is_64bit_file(const char *file) strstr(file, "64.exe") != nullptr; } -static inline bool has_str(const char *file, const char *str) -{ - return (file && str) ? (strstr(file, str) != nullptr) : false; -} - #define UTF8ToWideBuf(wide, utf8) UTF8ToWide(wide, _countof(wide), utf8) #define WideToUTF8Buf(utf8, wide) WideToUTF8(utf8, _countof(utf8), wide) #define UPDATE_URL L"https://cdn-fastly.obsproject.com/update_studio" -static bool AddPackageUpdateFiles(json_t *root, size_t idx, +static bool AddPackageUpdateFiles(const Json &root, size_t idx, const wchar_t *tempPath) { - json_t *package = json_array_get(root, idx); - json_t *name = json_object_get(package, "name"); - json_t *files = json_object_get(package, "files"); + const Json &package = root[idx]; + const Json &name = package["name"]; + const Json &files = package["files"]; bool isWin64 = is_64bit_windows(); - if (!json_is_array(files)) + if (!files.is_array()) return true; - if (!json_is_string(name)) + if (!name.is_string()) return true; wchar_t wPackageName[512]; - const char *packageName = json_string_value(name); - size_t fileCount = json_array_size(files); + const string &packageName = name.string_value(); + size_t fileCount = files.array_items().size(); - if (!UTF8ToWideBuf(wPackageName, packageName)) + if (!UTF8ToWideBuf(wPackageName, packageName.c_str())) return false; - if (strcmp(packageName, "core") != 0 && - !NonCorePackageInstalled(packageName)) + if (packageName != "core" && + !NonCorePackageInstalled(packageName.c_str())) return true; for (size_t j = 0; j < fileCount; j++) { - json_t *file = json_array_get(files, j); - json_t *fileName = json_object_get(file, "name"); - json_t *hash = json_object_get(file, "hash"); - json_t *size = json_object_get(file, "size"); + const Json &file = files[j]; + const Json &fileName = file["name"]; + const Json &hash = file["hash"]; + const Json &size = file["size"]; - if (!json_is_string(fileName)) + if (!fileName.is_string()) continue; - if (!json_is_string(hash)) + if (!hash.is_string()) continue; - if (!json_is_integer(size)) + if (!size.is_number()) continue; - const char *fileUTF8 = json_string_value(fileName); - const char *hashUTF8 = json_string_value(hash); - int fileSize = (int)json_integer_value(size); + const string &fileUTF8 = fileName.string_value(); + const string &hashUTF8 = hash.string_value(); + int fileSize = size.int_value(); - if (strlen(hashUTF8) != BLAKE2_HASH_LENGTH * 2) + if (hashUTF8.size() != BLAKE2_HASH_LENGTH * 2) continue; - if (!isWin64 && is_64bit_file(fileUTF8)) + if (!isWin64 && is_64bit_file(fileUTF8.c_str())) continue; /* ignore update files of opposite arch to reduce download */ - if ((is32bit && has_str(fileUTF8, "/64bit/")) || - (!is32bit && has_str(fileUTF8, "/32bit/"))) + if ((is32bit && fileUTF8.find("/64bit/") != string::npos) || + (!is32bit && fileUTF8.find("/32bit/") != string::npos)) continue; /* convert strings to wide */ @@ -674,9 +672,9 @@ static bool AddPackageUpdateFiles(json_t *root, size_t idx, wchar_t updateHashStr[BLAKE2_HASH_STR_LENGTH]; wchar_t tempFilePath[MAX_PATH]; - if (!UTF8ToWideBuf(updateFileName, fileUTF8)) + if (!UTF8ToWideBuf(updateFileName, fileUTF8.c_str())) continue; - if (!UTF8ToWideBuf(updateHashStr, hashUTF8)) + if (!UTF8ToWideBuf(updateHashStr, hashUTF8.c_str())) continue; /* make sure paths are safe */ @@ -928,7 +926,7 @@ static wchar_t tempPath[MAX_PATH] = {}; L"https://obsproject.com/update_studio/getpatchmanifest" #define HASH_NULL L"0000000000000000000000000000000000000000" -static bool UpdateVS2017Redists(json_t *root) +static bool UpdateVS2019Redists(const Json &root) { /* ------------------------------------------ * * Initialize session */ @@ -965,10 +963,10 @@ static bool UpdateVS2017Redists(json_t *root) /* ------------------------------------------ * * Download redist */ - Status(L"Downloading %s", L"Visual C++ 2017 Redistributable"); + Status(L"Downloading %s", L"Visual C++ 2019 Redistributable"); - const wchar_t *file = (is32bit) ? L"vc2017redist_x86.exe" - : L"vc2017redist_x64.exe"; + const wchar_t *file = (is32bit) ? L"VC_redist.x86.exe" + : L"VC_redist.x64.exe"; wstring sourceURL; sourceURL += L"https://cdn-fastly.obsproject.com/downloads/"; @@ -985,25 +983,25 @@ static bool UpdateVS2017Redists(json_t *root) DeleteFile(destPath.c_str()); Status(L"Update failed: Could not download " L"%s (error code %d)", - L"Visual C++ 2017 Redistributable", responseCode); + L"Visual C++ 2019 Redistributable", responseCode); return false; } /* ------------------------------------------ * * Get expected hash */ - json_t *redistJson = json_object_get( - root, is32bit ? "vc2017_redist_x86" : "vc2017_redist_x64"); - if (!redistJson) { - Status(L"Update failed: Could not parse VC2017 redist json"); + const char *which = is32bit ? "vc2019_redist_x86" : "vc2019_redist_x64"; + const Json &redistJson = root[which]; + if (!redistJson.is_string()) { + Status(L"Update failed: Could not parse VC2019 redist json"); return false; } - const char *expectedHashUTF8 = json_string_value(redistJson); + const string &expectedHashUTF8 = redistJson.string_value(); wchar_t expectedHashWide[BLAKE2_HASH_STR_LENGTH]; BYTE expectedHash[BLAKE2_HASH_LENGTH]; - if (!UTF8ToWideBuf(expectedHashWide, expectedHashUTF8)) { + if (!UTF8ToWideBuf(expectedHashWide, expectedHashUTF8.c_str())) { DeleteFile(destPath.c_str()); Status(L"Update failed: Couldn't convert Json for redist hash"); return false; @@ -1020,7 +1018,7 @@ static bool UpdateVS2017Redists(json_t *root) if (!CalculateFileHash(destPath.c_str(), downloadHash)) { DeleteFile(destPath.c_str()); Status(L"Update failed: Couldn't verify integrity of %s", - L"Visual C++ 2017 Redistributable"); + L"Visual C++ 2019 Redistributable"); return false; } @@ -1031,7 +1029,7 @@ static bool UpdateVS2017Redists(json_t *root) if (wcscmp(expectedHashWide, downloadHashWide) != 0) { DeleteFile(destPath.c_str()); Status(L"Update failed: Couldn't verify integrity of %s", - L"Visual C++ 2017 Redistributable"); + L"Visual C++ 2019 Redistributable"); return false; } @@ -1050,7 +1048,7 @@ static bool UpdateVS2017Redists(json_t *root) nullptr, false, CREATE_NO_WINDOW, nullptr, nullptr, &si, &pi); if (success) { - Status(L"Installing %s...", L"Visual C++ 2017 Redistributable"); + Status(L"Installing %s...", L"Visual C++ 2019 Redistributable"); CloseHandle(pi.hThread); WaitForSingleObject(pi.hProcess, INFINITE); @@ -1058,7 +1056,7 @@ static bool UpdateVS2017Redists(json_t *root) } else { Status(L"Update failed: Could not execute " L"%s (error code %d)", - L"Visual C++ 2017 Redistributable", (int)GetLastError()); + L"Visual C++ 2019 Redistributable", (int)GetLastError()); } DeleteFile(destPath.c_str()); @@ -1218,18 +1216,18 @@ static bool Update(wchar_t *cmdLine) return false; } - json_error_t error; - root = json_loads(manifestFile.c_str(), 0, &error); + string error; + root = Json::parse(manifestFile, error); - if (!root) { + if (!error.empty()) { Status(L"Update failed: Couldn't parse update " L"manifest: %S", - error.text); + error.c_str()); return false; } } - if (!json_is_object(root.get())) { + if (!root.is_object()) { Status(L"Update failed: Invalid update manifest"); return false; } @@ -1237,10 +1235,8 @@ static bool Update(wchar_t *cmdLine) /* ------------------------------------- * * Parse current manifest update files */ - json_t *packages = json_object_get(root, "packages"); - size_t packageCount = json_array_size(packages); - - for (size_t i = 0; i < packageCount; i++) { + const Json::array &packages = root["packages"].array_items(); + for (size_t i = 0; i < packages.size(); i++) { if (!AddPackageUpdateFiles(packages, i, tempPath)) { Status(L"Update failed: Failed to process update packages"); return false; @@ -1260,10 +1256,10 @@ static bool Update(wchar_t *cmdLine) } /* ------------------------------------- * - * Check for VS2017 redistributables */ + * Check for VS2019 redistributables */ - if (!HasVS2017Redist()) { - if (!UpdateVS2017Redists(root)) { + if (!HasVS2019Redist()) { + if (!UpdateVS2019Redists(root)) { return false; } } @@ -1271,7 +1267,7 @@ static bool Update(wchar_t *cmdLine) /* ------------------------------------- * * Generate file hash json */ - Json files(json_array()); + Json::array files; for (update_t &update : updates) { wchar_t whash_string[BLAKE2_HASH_STR_LENGTH]; @@ -1296,10 +1292,10 @@ static bool Update(wchar_t *cmdLine) package_path += "/"; package_path += outputPath; - json_t *obj = json_object(); - json_object_set(obj, "name", json_string(package_path.c_str())); - json_object_set(obj, "hash", json_string(hash_string)); - json_array_append_new(files, obj); + files.emplace_back(Json::object{ + {"name", package_path}, + {"hash", hash_string}, + }); } /* ------------------------------------- * @@ -1307,18 +1303,20 @@ static bool Update(wchar_t *cmdLine) string newManifest; - if (json_array_size(files) > 0) { - char *post_body = json_dumps(files, JSON_COMPACT); + if (files.size() > 0) { + string post_body; + Json(files).dump(post_body); int responseCode; - int len = (int)strlen(post_body); + int len = (int)post_body.size(); uLong compressSize = compressBound(len); string compressedJson; compressedJson.resize(compressSize); compress2((Bytef *)&compressedJson[0], &compressSize, - (const Bytef *)post_body, len, Z_BEST_COMPRESSION); + (const Bytef *)post_body.c_str(), len, + Z_BEST_COMPRESSION); compressedJson.resize(compressSize); bool success = !!HTTPPostData(PATCH_MANIFEST_URL, @@ -1326,7 +1324,6 @@ static bool Update(wchar_t *cmdLine) (int)compressedJson.size(), L"Accept-Encoding: gzip", &responseCode, newManifest); - free(post_body); if (!success) return false; @@ -1344,49 +1341,50 @@ static bool Update(wchar_t *cmdLine) /* ------------------------------------- * * Parse new manifest */ - json_error_t error; - root = json_loads(newManifest.c_str(), 0, &error); - if (!root) { + string error; + root = Json::parse(newManifest, error); + if (!error.empty()) { Status(L"Update failed: Couldn't parse patch manifest: %S", - error.text); + error.c_str()); return false; } - if (!json_is_array(root.get())) { + if (!root.is_array()) { Status(L"Update failed: Invalid patch manifest"); return false; } - packageCount = json_array_size(root); + size_t packageCount = root.array_items().size(); for (size_t i = 0; i < packageCount; i++) { - json_t *patch = json_array_get(root, i); + const Json &patch = root[i]; - if (!json_is_object(patch)) { + if (!patch.is_object()) { Status(L"Update failed: Invalid patch manifest"); return false; } - json_t *name_json = json_object_get(patch, "name"); - json_t *hash_json = json_object_get(patch, "hash"); - json_t *source_json = json_object_get(patch, "source"); - json_t *size_json = json_object_get(patch, "size"); + const Json &name_json = patch["name"]; + const Json &hash_json = patch["hash"]; + const Json &source_json = patch["source"]; + const Json &size_json = patch["size"]; - if (!json_is_string(name_json)) + if (!name_json.is_string()) continue; - if (!json_is_string(hash_json)) + if (!hash_json.is_string()) continue; - if (!json_is_string(source_json)) + if (!source_json.is_string()) continue; - if (!json_is_integer(size_json)) + if (!size_json.is_number()) continue; - const char *name = json_string_value(name_json); - const char *hash = json_string_value(hash_json); - const char *source = json_string_value(source_json); - int size = (int)json_integer_value(size_json); + const string &name = name_json.string_value(); + const string &hash = hash_json.string_value(); + const string &source = source_json.string_value(); + int size = size_json.int_value(); - UpdateWithPatchIfAvailable(name, hash, source, size); + UpdateWithPatchIfAvailable(name.c_str(), hash.c_str(), + source.c_str(), size); } /* ------------------------------------- * diff --git a/UI/win-update/updater/updater.hpp b/UI/win-update/updater/updater.hpp index 1297ce6..812d1da 100644 --- a/UI/win-update/updater/updater.hpp +++ b/UI/win-update/updater/updater.hpp @@ -74,7 +74,7 @@ #endif #include -#include +#include #include "resource.h" bool HTTPGetFile(HINTERNET hConnect, const wchar_t *url, diff --git a/UI/win-update/win-update-helpers.hpp b/UI/win-update/win-update-helpers.hpp index ef6aa59..3f7040c 100644 --- a/UI/win-update/win-update-helpers.hpp +++ b/UI/win-update/win-update-helpers.hpp @@ -4,8 +4,6 @@ #include #include -#include - #include #include @@ -69,72 +67,5 @@ public: /* ------------------------------------------------------------------------ */ -class Json { - json_t *json; - -public: - inline Json() : json(nullptr) {} - explicit inline Json(json_t *json_) : json(json_) {} - inline Json(const Json &from) : json(json_incref(from.json)) {} - inline Json(Json &&from) : json(from.json) { from.json = nullptr; } - - inline ~Json() - { - if (json) - json_decref(json); - } - - inline Json &operator=(json_t *json_) - { - if (json) - json_decref(json); - json = json_; - return *this; - } - inline Json &operator=(const Json &from) - { - if (json) - json_decref(json); - json = json_incref(from.json); - return *this; - } - inline Json &operator=(Json &&from) - { - if (json) - json_decref(json); - json = from.json; - from.json = nullptr; - return *this; - } - - inline operator json_t *() const { return json; } - - inline bool operator!() const { return !json; } - - inline const char *GetString(const char *name, - const char *def = nullptr) const - { - json_t *obj(json_object_get(json, name)); - if (!obj) - return def; - return json_string_value(obj); - } - inline int64_t GetInt(const char *name, int def = 0) const - { - json_t *obj(json_object_get(json, name)); - if (!obj) - return def; - return json_integer_value(obj); - } - inline json_t *GetObject(const char *name) const - { - return json_object_get(json, name); - } - - inline json_t *get() const { return json; } -}; - -/* ------------------------------------------------------------------------ */ - std::string vstrprintf(const char *format, va_list args); std::string strprintf(const char *format, ...); diff --git a/UI/win-update/win-update.cpp b/UI/win-update/win-update.cpp index 9371a8c..2722ee7 100644 --- a/UI/win-update/win-update.cpp +++ b/UI/win-update/win-update.cpp @@ -12,7 +12,7 @@ #include #include -#include +#include #include #include @@ -25,6 +25,7 @@ #endif using namespace std; +using namespace json11; struct QCef; extern QCef *cef; @@ -402,31 +403,31 @@ static bool ParseUpdateManifest(const char *manifest, bool *updatesAvailable, string ¬es_str, int &updateVer) try { - json_error_t error; - Json root(json_loads(manifest, 0, &error)); - if (!root) - throw strprintf("Failed reading json string (%d): %s", - error.line, error.text); + string error; + Json root = Json::parse(manifest, error); + if (!error.empty()) + throw strprintf("Failed reading json string: %s", + error.c_str()); - if (!json_is_object(root.get())) + if (!root.is_object()) throw string("Root of manifest is not an object"); - int major = root.GetInt("version_major"); - int minor = root.GetInt("version_minor"); - int patch = root.GetInt("version_patch"); + int major = root["version_major"].int_value(); + int minor = root["version_minor"].int_value(); + int patch = root["version_patch"].int_value(); if (major == 0) throw strprintf("Invalid version number: %d.%d.%d", major, minor, patch); - json_t *notes = json_object_get(root, "notes"); - if (!json_is_string(notes)) + const Json ¬es = root["notes"]; + if (!notes.is_string()) throw string("'notes' value invalid"); - notes_str = json_string_value(notes); + notes_str = notes.string_value(); - json_t *packages = json_object_get(root, "packages"); - if (!json_is_array(packages)) + const Json &packages = root["packages"]; + if (!packages.is_array()) throw string("'packages' value invalid"); int cur_ver = LIBOBS_API_VER; diff --git a/UI/window-basic-auto-config-test.cpp b/UI/window-basic-auto-config-test.cpp index c41f1c1..a5ba9bd 100644 --- a/UI/window-basic-auto-config-test.cpp +++ b/UI/window-basic-auto-config-test.cpp @@ -963,6 +963,27 @@ void AutoConfigTestPage::TestRecordingEncoderThread() #define QUALITY_SAME "Basic.Settings.Output.Simple.RecordingQuality.Stream" #define QUALITY_HIGH "Basic.Settings.Output.Simple.RecordingQuality.Small" +void set_closest_res(int &cx, int &cy, struct obs_service_resolution *res_list, + size_t count) +{ + int best_pixel_diff = 0x7FFFFFFF; + int start_cx = cx; + int start_cy = cy; + + for (size_t i = 0; i < count; i++) { + struct obs_service_resolution &res = res_list[i]; + int pixel_cx_diff = abs(start_cx - res.cx); + int pixel_cy_diff = abs(start_cy - res.cy); + int pixel_diff = pixel_cx_diff + pixel_cy_diff; + + if (pixel_diff < best_pixel_diff) { + best_pixel_diff = pixel_diff; + cx = res.cx; + cy = res.cy; + } + } +} + void AutoConfigTestPage::FinalizeResults() { ui->stackedWidget->setCurrentIndex(1); @@ -1013,6 +1034,27 @@ void AutoConfigTestPage::FinalizeResults() obs_service_apply_encoder_settings(service, vencoder_settings, nullptr); + struct obs_service_resolution *res_list; + size_t res_count; + int maxFPS; + obs_service_get_supported_resolutions(service, &res_list, + &res_count); + obs_service_get_max_fps(service, &maxFPS); + + if (res_list) { + set_closest_res(wiz->idealResolutionCX, + wiz->idealResolutionCY, res_list, + res_count); + } + if (maxFPS) { + double idealFPS = (double)wiz->idealFPSNum / + (double)wiz->idealFPSDen; + if (idealFPS > (double)maxFPS) { + wiz->idealFPSNum = maxFPS; + wiz->idealFPSDen = 1; + } + } + wiz->idealBitrate = (int)obs_data_get_int(vencoder_settings, "bitrate"); diff --git a/UI/window-basic-auto-config.cpp b/UI/window-basic-auto-config.cpp index 466da7e..66cdef6 100644 --- a/UI/window-basic-auto-config.cpp +++ b/UI/window-basic-auto-config.cpp @@ -285,6 +285,8 @@ AutoConfigStreamPage::AutoConfigStreamPage(QWidget *parent) connect(ui->service, SIGNAL(currentIndexChanged(int)), this, SLOT(UpdateKeyLink())); + connect(ui->service, SIGNAL(currentIndexChanged(int)), this, + SLOT(UpdateMoreInfoLink())); connect(ui->key, SIGNAL(textChanged(const QString &)), this, SLOT(UpdateCompleted())); @@ -575,6 +577,35 @@ void AutoConfigStreamPage::ServiceChanged() UpdateCompleted(); } +void AutoConfigStreamPage::UpdateMoreInfoLink() +{ + if (IsCustomService()) { + ui->moreInfoButton->hide(); + return; + } + + QString serviceName = ui->service->currentText(); + obs_properties_t *props = obs_get_service_properties("rtmp_common"); + obs_property_t *services = obs_properties_get(props, "service"); + + OBSData settings = obs_data_create(); + obs_data_release(settings); + + obs_data_set_string(settings, "service", QT_TO_UTF8(serviceName)); + obs_property_modified(services, settings); + + const char *more_info_link = + obs_data_get_string(settings, "more_info_link"); + + if (!more_info_link || (*more_info_link == '\0')) { + ui->moreInfoButton->hide(); + } else { + ui->moreInfoButton->setTargetUrl(QUrl(more_info_link)); + ui->moreInfoButton->show(); + } + obs_properties_destroy(props); +} + void AutoConfigStreamPage::UpdateKeyLink() { QString serviceName = ui->service->currentText(); @@ -583,9 +614,8 @@ void AutoConfigStreamPage::UpdateKeyLink() QString streamKeyLink; if (serviceName == "Twitch") { - streamKeyLink = - "https://www.twitch.tv/broadcast/dashboard/streamkey"; - } else if (serviceName == "YouTube / YouTube Gaming") { + streamKeyLink = "https://dashboard.twitch.tv/settings/stream"; + } else if (serviceName.startsWith("YouTube")) { streamKeyLink = "https://www.youtube.com/live_dashboard"; isYoutube = true; } else if (serviceName.startsWith("Restream.io")) { @@ -814,6 +844,7 @@ AutoConfig::AutoConfig(QWidget *parent) : QWizard(parent) streamPage->UpdateServerList(); streamPage->UpdateKeyLink(); + streamPage->UpdateMoreInfoLink(); streamPage->lastService.clear(); if (!customServer) { diff --git a/UI/window-basic-auto-config.hpp b/UI/window-basic-auto-config.hpp index 98540c8..656b76f 100644 --- a/UI/window-basic-auto-config.hpp +++ b/UI/window-basic-auto-config.hpp @@ -195,6 +195,7 @@ public slots: void on_useStreamKey_clicked(); void ServiceChanged(); void UpdateKeyLink(); + void UpdateMoreInfoLink(); void UpdateServerList(); void UpdateCompleted(); }; diff --git a/UI/window-basic-filters.cpp b/UI/window-basic-filters.cpp index bffa3d8..d27e59f 100644 --- a/UI/window-basic-filters.cpp +++ b/UI/window-basic-filters.cpp @@ -225,7 +225,7 @@ void OBSBasicFilters::UpdateProperties(void *data, calldata_t *) "ReloadProperties"); } -void OBSBasicFilters::AddFilter(OBSSource filter) +void OBSBasicFilters::AddFilter(OBSSource filter, bool focus) { uint32_t flags = obs_source_get_output_flags(filter); bool async = (flags & OBS_SOURCE_ASYNC) != 0; @@ -238,7 +238,8 @@ void OBSBasicFilters::AddFilter(OBSSource filter) item->setData(Qt::UserRole, QVariant::fromValue(filter)); list->addItem(item); - list->setCurrentItem(item); + if (focus) + list->setCurrentItem(item); SetupVisibilityItem(list, item, filter); } @@ -352,10 +353,16 @@ void OBSBasicFilters::UpdateFilters() OBSBasicFilters *window = reinterpret_cast(p); - window->AddFilter(filter); + window->AddFilter(filter, false); }, this); + if (ui->asyncFilters->count() > 0) { + ui->asyncFilters->setCurrentItem(ui->asyncFilters->item(0)); + } else if (ui->effectFilters->count() > 0) { + ui->effectFilters->setCurrentItem(ui->effectFilters->item(0)); + } + main->SaveProject(); } @@ -732,17 +739,40 @@ void OBSBasicFilters::CustomContextMenu(const QPoint &pos, bool async) popup.addMenu(addMenu); if (item) { + const char *dulpicateSlot = + async ? SLOT(DuplicateAsyncFilter()) + : SLOT(DuplicateEffectFilter()); + const char *renameSlot = async ? SLOT(RenameAsyncFilter()) : SLOT(RenameEffectFilter()); const char *removeSlot = async ? SLOT(on_removeAsyncFilter_clicked()) : SLOT(on_removeEffectFilter_clicked()); + popup.addSeparator(); + popup.addAction(QTStr("Duplicate"), this, dulpicateSlot); popup.addSeparator(); popup.addAction(QTStr("Rename"), this, renameSlot); popup.addAction(QTStr("Remove"), this, removeSlot); + popup.addSeparator(); + + QAction *copyAction = new QAction(QTStr("Copy")); + connect(copyAction, SIGNAL(triggered()), this, + SLOT(CopyFilter())); + copyAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_C)); + ui->effectWidget->addAction(copyAction); + ui->asyncWidget->addAction(copyAction); + popup.addAction(copyAction); } + QAction *pasteAction = new QAction(QTStr("Paste")); + pasteAction->setEnabled(main->copyFilter); + connect(pasteAction, SIGNAL(triggered()), this, SLOT(PasteFilter())); + pasteAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_V)); + ui->effectWidget->addAction(pasteAction); + ui->asyncWidget->addAction(pasteAction); + popup.addAction(pasteAction); + popup.exec(QCursor::pos()); } @@ -764,6 +794,58 @@ void OBSBasicFilters::EditItem(QListWidgetItem *item, bool async) editActive = true; } +void OBSBasicFilters::DuplicateItem(QListWidgetItem *item) +{ + OBSSource filter = item->data(Qt::UserRole).value(); + string name = obs_source_get_name(filter); + obs_source_t *existing_filter; + + QString placeholder = QString::fromStdString(name); + QString text{placeholder}; + int i = 2; + while ((existing_filter = obs_source_get_filter_by_name( + source, QT_TO_UTF8(text)))) { + obs_source_release(existing_filter); + text = QString("%1 %2").arg(placeholder).arg(i++); + } + + bool success = NameDialog::AskForName( + this, QTStr("Basic.Filters.AddFilter.Title"), + QTStr("Basic.Filters.AddFilter.Text"), name, text); + if (!success) + return; + + if (name.empty()) { + OBSMessageBox::warning(this, QTStr("NoNameEntered.Title"), + QTStr("NoNameEntered.Text")); + DuplicateItem(item); + return; + } + + existing_filter = obs_source_get_filter_by_name(source, name.c_str()); + if (existing_filter) { + OBSMessageBox::warning(this, QTStr("NameExists.Title"), + QTStr("NameExists.Text")); + obs_source_release(existing_filter); + DuplicateItem(item); + return; + } + bool enabled = obs_source_enabled(filter); + obs_source_t *new_filter = + obs_source_duplicate(filter, name.c_str(), false); + if (new_filter) { + const char *sourceName = obs_source_get_name(source); + const char *id = obs_source_get_id(new_filter); + blog(LOG_INFO, + "User duplicated filter '%s' (%s) from '%s' " + "to source '%s'", + name.c_str(), id, name.c_str(), sourceName); + obs_source_set_enabled(new_filter, enabled); + obs_source_filter_add(source, new_filter); + obs_source_release(new_filter); + } +} + void OBSBasicFilters::on_asyncFilters_customContextMenuRequested( const QPoint &pos) { @@ -786,6 +868,16 @@ void OBSBasicFilters::RenameEffectFilter() EditItem(ui->effectFilters->currentItem(), false); } +void OBSBasicFilters::DuplicateAsyncFilter() +{ + DuplicateItem(ui->asyncFilters->currentItem()); +} + +void OBSBasicFilters::DuplicateEffectFilter() +{ + DuplicateItem(ui->effectFilters->currentItem()); +} + void OBSBasicFilters::FilterNameEdited(QWidget *editor, QListWidget *list) { QListWidgetItem *listItem = list->currentItem(); @@ -864,3 +956,24 @@ void OBSBasicFilters::ResetFilters() view->RefreshProperties(); } + +void OBSBasicFilters::CopyFilter() +{ + OBSSource filter = nullptr; + + if (isAsync) + filter = GetFilter(ui->asyncFilters->currentRow(), true); + else + filter = GetFilter(ui->effectFilters->currentRow(), false); + + main->copyFilter = OBSGetWeakRef(filter); +} + +void OBSBasicFilters::PasteFilter() +{ + OBSSource filter = OBSGetStrongRef(main->copyFilter); + if (!filter) + return; + + obs_source_copy_single_filter(source, filter); +} diff --git a/UI/window-basic-filters.hpp b/UI/window-basic-filters.hpp index ff7f5d1..52e93e4 100644 --- a/UI/window-basic-filters.hpp +++ b/UI/window-basic-filters.hpp @@ -67,6 +67,7 @@ private: void CustomContextMenu(const QPoint &pos, bool async); void EditItem(QListWidgetItem *item, bool async); + void DuplicateItem(QListWidgetItem *item); void FilterNameEdited(QWidget *editor, QListWidget *list); @@ -77,11 +78,13 @@ private: bool editActive = false; private slots: - void AddFilter(OBSSource filter); + void AddFilter(OBSSource filter, bool focus = true); void RemoveFilter(OBSSource filter); void ReorderFilters(); void RenameAsyncFilter(); void RenameEffectFilter(); + void DuplicateAsyncFilter(); + void DuplicateEffectFilter(); void ResetFilters(); void AddFilterFromAction(); @@ -111,6 +114,9 @@ private slots: void EffectFilterNameEdited(QWidget *editor, QAbstractItemDelegate::EndEditHint endHint); + void CopyFilter(); + void PasteFilter(); + public: OBSBasicFilters(QWidget *parent, OBSSource source_); ~OBSBasicFilters(); diff --git a/UI/window-basic-interaction.cpp b/UI/window-basic-interaction.cpp index 333a263..ed3519c 100644 --- a/UI/window-basic-interaction.cpp +++ b/UI/window-basic-interaction.cpp @@ -218,6 +218,14 @@ static int TranslateQtMouseEventModifiers(QMouseEvent *event) bool OBSBasicInteraction::GetSourceRelativeXY(int mouseX, int mouseY, int &relX, int &relY) { +#ifdef SUPPORTS_FRACTIONAL_SCALING + float pixelRatio = devicePixelRatioF(); +#else + float pixelRatio = devicePixelRatio(); +#endif + int mouseXscaled = (int)roundf(mouseX * pixelRatio); + int mouseYscaled = (int)roundf(mouseY * pixelRatio); + QSize size = GetPixelSize(ui->preview); uint32_t sourceCX = max(obs_source_get_width(source), 1u); @@ -230,11 +238,11 @@ bool OBSBasicInteraction::GetSourceRelativeXY(int mouseX, int mouseY, int &relX, y, scale); if (x > 0) { - relX = int(float(mouseX - x) / scale); - relY = int(float(mouseY / scale)); + relX = int(float(mouseXscaled - x) / scale); + relY = int(float(mouseYscaled / scale)); } else { - relX = int(float(mouseX / scale)); - relY = int(float(mouseY - y) / scale); + relX = int(float(mouseXscaled / scale)); + relY = int(float(mouseYscaled - y) / scale); } // Confirm mouse is inside the source diff --git a/UI/window-basic-main-outputs.cpp b/UI/window-basic-main-outputs.cpp index 6892db1..68cc566 100644 --- a/UI/window-basic-main-outputs.cpp +++ b/UI/window-basic-main-outputs.cpp @@ -140,6 +140,13 @@ static void OBSReplayBufferStopping(void *data, calldata_t *params) UNUSED_PARAMETER(params); } +static void OBSReplayBufferSaved(void *data, calldata_t *) +{ + BasicOutputHandler *output = static_cast(data); + QMetaObject::invokeMethod(output->main, "ReplayBufferSaved", + Qt::QueuedConnection); +} + static void OBSStartVirtualCam(void *data, calldata_t *params) { BasicOutputHandler *output = static_cast(data); @@ -242,10 +249,12 @@ struct SimpleOutput : BasicOutputHandler { OBSEncoder aacStreaming; OBSEncoder h264Streaming; OBSEncoder aacRecording; + OBSEncoder aacArchive; OBSEncoder h264Recording; string aacRecEncID; string aacStreamEncID; + string aacArchiveEncID; string videoEncoder; string videoQuality; @@ -279,6 +288,8 @@ struct SimpleOutput : BasicOutputHandler { void UpdateRecording(); bool ConfigureRecording(bool useReplayBuffer); + void SetupVodTrack(obs_service_t *service); + virtual bool SetupStreaming(obs_service_t *service) override; virtual bool StartStreaming(obs_service_t *service) override; virtual bool StartRecording() override; @@ -379,6 +390,8 @@ void SimpleOutput::LoadRecordingPreset() } } +#define SIMPLE_ARCHIVE_NAME "simple_archive_aac" + SimpleOutput::SimpleOutput(OBSBasic *main_) : BasicOutputHandler(main_) { const char *encoder = config_get_string(main->Config(), "SimpleOutput", @@ -402,6 +415,9 @@ SimpleOutput::SimpleOutput(OBSBasic *main_) : BasicOutputHandler(main_) if (!CreateAACEncoder(aacStreaming, aacStreamEncID, GetAudioBitrate(), "simple_aac", 0)) throw "Failed to create aac streaming encoder (simple output)"; + if (!CreateAACEncoder(aacArchive, aacArchiveEncID, GetAudioBitrate(), + SIMPLE_ARCHIVE_NAME, 1)) + throw "Failed to create aac arhive encoder (simple output)"; LoadRecordingPreset(); @@ -437,6 +453,8 @@ SimpleOutput::SimpleOutput(OBSBasic *main_) : BasicOutputHandler(main_) replayBufferStopping.Connect(signal, "stopping", OBSReplayBufferStopping, this); + replayBufferSaved.Connect(signal, "saved", + OBSReplayBufferSaved, this); } fileOutput = obs_output_create( @@ -473,8 +491,8 @@ void SimpleOutput::Update() int audioBitrate = GetAudioBitrate(); bool advanced = config_get_bool(main->Config(), "SimpleOutput", "UseAdvanced"); - bool enforceBitrate = config_get_bool(main->Config(), "SimpleOutput", - "EnforceBitrate"); + bool enforceBitrate = !config_get_bool(main->Config(), "Stream1", + "IgnoreRecommended"); const char *custom = config_get_string(main->Config(), "SimpleOutput", "x264Settings"); const char *encoder = config_get_string(main->Config(), "SimpleOutput", @@ -512,7 +530,7 @@ void SimpleOutput::Update() obs_service_apply_encoder_settings(main->GetService(), h264Settings, aacSettings); - if (advanced && !enforceBitrate) { + if (!enforceBitrate) { obs_data_set_int(h264Settings, "bitrate", videoBitrate); obs_data_set_int(aacSettings, "bitrate", audioBitrate); } @@ -526,6 +544,7 @@ void SimpleOutput::Update() obs_encoder_update(h264Streaming, h264Settings); obs_encoder_update(aacStreaming, aacSettings); + obs_encoder_update(aacArchive, aacSettings); obs_data_release(h264Settings); obs_data_release(aacSettings); @@ -700,6 +719,7 @@ inline void SimpleOutput::SetupOutputs() SimpleOutput::Update(); obs_encoder_set_video(h264Streaming, obs_get_video()); obs_encoder_set_audio(aacStreaming, obs_get_audio()); + obs_encoder_set_audio(aacArchive, obs_get_audio()); if (usingRecordingPreset) { if (ffmpegOutput) { @@ -824,6 +844,51 @@ bool SimpleOutput::SetupStreaming(obs_service_t *service) return true; } +static inline bool ServiceSupportsVodTrack(const char *service); + +static void clear_archive_encoder(obs_output_t *output, + const char *expected_name) +{ + obs_encoder_t *last = obs_output_get_audio_encoder(output, 1); + bool clear = false; + + /* ensures that we don't remove twitch's soundtrack encoder */ + if (last) { + const char *name = obs_encoder_get_name(last); + clear = name && strcmp(name, expected_name) == 0; + obs_encoder_release(last); + } + + if (clear) + obs_output_set_audio_encoder(output, nullptr, 1); +} + +void SimpleOutput::SetupVodTrack(obs_service_t *service) +{ + bool advanced = + config_get_bool(main->Config(), "SimpleOutput", "UseAdvanced"); + bool enable = config_get_bool(main->Config(), "SimpleOutput", + "VodTrackEnabled"); + bool enableForCustomServer = config_get_bool( + GetGlobalConfig(), "General", "EnableCustomServerVodTrack"); + + obs_data_t *settings = obs_service_get_settings(service); + const char *name = obs_data_get_string(settings, "service"); + + const char *id = obs_service_get_id(service); + if (strcmp(id, "rtmp_custom") == 0) + enable = enableForCustomServer ? enable : false; + else + enable = advanced && enable && ServiceSupportsVodTrack(name); + + if (enable) + obs_output_set_audio_encoder(streamOutput, aacArchive, 1); + else + clear_archive_encoder(streamOutput, SIMPLE_ARCHIVE_NAME); + + obs_data_release(settings); +} + bool SimpleOutput::StartStreaming(obs_service_t *service) { bool reconnect = config_get_bool(main->Config(), "Output", "Reconnect"); @@ -863,6 +928,8 @@ bool SimpleOutput::StartStreaming(obs_service_t *service) obs_output_set_reconnect_settings(streamOutput, maxRetries, retryDelay); + SetupVodTrack(service); + if (obs_output_start(streamOutput)) { return true; } @@ -1045,6 +1112,7 @@ bool SimpleOutput::ReplayBufferActive() const struct AdvancedOutput : BasicOutputHandler { OBSEncoder streamAudioEnc; + OBSEncoder streamArchiveEnc; OBSEncoder aacTrack[MAX_AUDIO_MIXES]; OBSEncoder h264Streaming; OBSEncoder h264Recording; @@ -1063,6 +1131,8 @@ struct AdvancedOutput : BasicOutputHandler { inline void UpdateAudioSettings(); virtual void Update() override; + inline void SetupVodTrack(obs_service_t *service); + inline void SetupStreaming(); inline void SetupRecording(); inline void SetupFFmpeg(); @@ -1112,6 +1182,8 @@ static void ApplyEncoderDefaults(OBSData &settings, settings = std::move(dataRet); } +#define ADV_ARCHIVE_NAME "adv_archive_aac" + AdvancedOutput::AdvancedOutput(OBSBasic *main_) : BasicOutputHandler(main_) { const char *recType = @@ -1130,15 +1202,6 @@ AdvancedOutput::AdvancedOutput(OBSBasic *main_) : BasicOutputHandler(main_) OBSData streamEncSettings = GetDataFromJsonFile("streamEncoder.json"); OBSData recordEncSettings = GetDataFromJsonFile("recordEncoder.json"); - const char *rate_control = obs_data_get_string( - useStreamEncoder ? streamEncSettings : recordEncSettings, - "rate_control"); - if (!rate_control) - rate_control = ""; - usesBitrate = astrcmpi(rate_control, "CBR") == 0 || - astrcmpi(rate_control, "VBR") == 0 || - astrcmpi(rate_control, "ABR") == 0; - if (ffmpegOutput) { fileOutput = obs_output_create( "ffmpeg_output", "adv_ffmpeg_output", nullptr, nullptr); @@ -1173,6 +1236,8 @@ AdvancedOutput::AdvancedOutput(OBSBasic *main_) : BasicOutputHandler(main_) replayBufferStopping.Connect(signal, "stopping", OBSReplayBufferStopping, this); + replayBufferSaved.Connect(signal, "saved", + OBSReplayBufferSaved, this); } fileOutput = obs_output_create( @@ -1200,6 +1265,15 @@ AdvancedOutput::AdvancedOutput(OBSBasic *main_) : BasicOutputHandler(main_) "(advanced output)"; obs_encoder_release(h264Streaming); + const char *rate_control = obs_data_get_string( + useStreamEncoder ? streamEncSettings : recordEncSettings, + "rate_control"); + if (!rate_control) + rate_control = ""; + usesBitrate = astrcmpi(rate_control, "CBR") == 0 || + astrcmpi(rate_control, "VBR") == 0 || + astrcmpi(rate_control, "ABR") == 0; + for (int i = 0; i < MAX_AUDIO_MIXES; i++) { char name[9]; sprintf(name, "adv_aac%d", i); @@ -1214,10 +1288,18 @@ AdvancedOutput::AdvancedOutput(OBSBasic *main_) : BasicOutputHandler(main_) int streamTrack = config_get_int(main->Config(), "AdvOut", "TrackIndex") - 1; if (!CreateAACEncoder(streamAudioEnc, id, GetAudioBitrate(streamTrack), - "avc_aac_stream", streamTrack)) + "adv_stream_aac", streamTrack)) throw "Failed to create streaming audio encoder " "(advanced output)"; + id = ""; + int vodTrack = + config_get_int(main->Config(), "AdvOut", "VodTrackIndex") - 1; + if (!CreateAACEncoder(streamArchiveEnc, id, GetAudioBitrate(vodTrack), + ADV_ARCHIVE_NAME, vodTrack)) + throw "Failed to create archive audio encoder " + "(advanced output)"; + startRecording.Connect(obs_output_get_signal_handler(fileOutput), "start", OBSStartRecording, this); stopRecording.Connect(obs_output_get_signal_handler(fileOutput), "stop", @@ -1230,6 +1312,8 @@ void AdvancedOutput::UpdateStreamSettings() { bool applyServiceSettings = config_get_bool(main->Config(), "AdvOut", "ApplyServiceSettings"); + bool enforceBitrate = !config_get_bool(main->Config(), "Stream1", + "IgnoreRecommended"); bool dynBitrate = config_get_bool(main->Config(), "Output", "DynamicBitrate"); const char *streamEncoder = @@ -1238,9 +1322,13 @@ void AdvancedOutput::UpdateStreamSettings() OBSData settings = GetDataFromJsonFile("streamEncoder.json"); ApplyEncoderDefaults(settings, h264Streaming); - if (applyServiceSettings) + if (applyServiceSettings) { + int bitrate = (int)obs_data_get_int(settings, "bitrate"); obs_service_apply_encoder_settings(main->GetService(), settings, nullptr); + if (!enforceBitrate) + obs_data_set_int(settings, "bitrate", bitrate); + } if (dynBitrate && astrcmpi(streamEncoder, "jim_nvenc") == 0) obs_data_set_bool(settings, "lookahead", false); @@ -1269,6 +1357,18 @@ void AdvancedOutput::Update() UpdateAudioSettings(); } +static inline bool ServiceSupportsVodTrack(const char *service) +{ + static const char *vodTrackServices[] = {"Twitch"}; + + for (const char *vodTrackService : vodTrackServices) { + if (astrcmpi(vodTrackService, service) == 0) + return true; + } + + return false; +} + inline void AdvancedOutput::SetupStreaming() { bool rescale = config_get_bool(main->Config(), "AdvOut", "Rescale"); @@ -1287,6 +1387,15 @@ inline void AdvancedOutput::SetupStreaming() obs_output_set_audio_encoder(streamOutput, streamAudioEnc, 0); obs_encoder_set_scaled_size(h264Streaming, cx, cy); obs_encoder_set_video(h264Streaming, obs_get_video()); + + const char *id = obs_service_get_id(main->GetService()); + if (strcmp(id, "rtmp_custom") == 0) { + obs_data_t *settings = obs_data_create(); + obs_service_apply_encoder_settings(main->GetService(), settings, + nullptr); + obs_encoder_update(h264Streaming, settings); + obs_data_release(settings); + } } inline void AdvancedOutput::SetupRecording() @@ -1439,8 +1548,12 @@ inline void AdvancedOutput::UpdateAudioSettings() { bool applyServiceSettings = config_get_bool(main->Config(), "AdvOut", "ApplyServiceSettings"); + bool enforceBitrate = !config_get_bool(main->Config(), "Stream1", + "IgnoreRecommended"); int streamTrackIndex = config_get_int(main->Config(), "AdvOut", "TrackIndex"); + int vodTrackIndex = + config_get_int(main->Config(), "AdvOut", "VodTrackIndex"); obs_data_t *settings[MAX_AUDIO_MIXES]; for (size_t i = 0; i < MAX_AUDIO_MIXES; i++) { @@ -1461,18 +1574,29 @@ inline void AdvancedOutput::UpdateAudioSettings() } for (size_t i = 0; i < MAX_AUDIO_MIXES; i++) { + int track = (int)(i + 1); + obs_encoder_update(aacTrack[i], settings[i]); - if ((int)(i + 1) == streamTrackIndex) { + if (track == streamTrackIndex || track == vodTrackIndex) { if (applyServiceSettings) { + int bitrate = (int)obs_data_get_int(settings[i], + "bitrate"); obs_service_apply_encoder_settings( main->GetService(), nullptr, settings[i]); - } - obs_encoder_update(streamAudioEnc, settings[i]); + if (!enforceBitrate) + obs_data_set_int(settings[i], "bitrate", + bitrate); + } } + if (track == streamTrackIndex) + obs_encoder_update(streamAudioEnc, settings[i]); + if (track == vodTrackIndex) + obs_encoder_update(streamArchiveEnc, settings[i]); + obs_data_release(settings[i]); } } @@ -1485,6 +1609,7 @@ void AdvancedOutput::SetupOutputs() for (size_t i = 0; i < MAX_AUDIO_MIXES; i++) obs_encoder_set_audio(aacTrack[i], obs_get_audio()); obs_encoder_set_audio(streamAudioEnc, obs_get_audio()); + obs_encoder_set_audio(streamArchiveEnc, obs_get_audio()); SetupStreaming(); @@ -1504,10 +1629,39 @@ int AdvancedOutput::GetAudioBitrate(size_t i) const return FindClosestAvailableAACBitrate(bitrate); } +inline void AdvancedOutput::SetupVodTrack(obs_service_t *service) +{ + int streamTrack = + config_get_int(main->Config(), "AdvOut", "TrackIndex"); + bool vodTrackEnabled = + config_get_bool(main->Config(), "AdvOut", "VodTrackEnabled"); + int vodTrackIndex = + config_get_int(main->Config(), "AdvOut", "VodTrackIndex"); + bool enableForCustomServer = config_get_bool( + GetGlobalConfig(), "General", "EnableCustomServerVodTrack"); + + const char *id = obs_service_get_id(service); + if (strcmp(id, "rtmp_custom") == 0) { + vodTrackEnabled = enableForCustomServer ? vodTrackEnabled + : false; + } else { + obs_data_t *settings = obs_service_get_settings(service); + const char *service = obs_data_get_string(settings, "service"); + if (!ServiceSupportsVodTrack(service)) + vodTrackEnabled = false; + obs_data_release(settings); + } + + if (vodTrackEnabled && streamTrack != vodTrackIndex) + obs_output_set_audio_encoder(streamOutput, streamArchiveEnc, 1); + else + clear_archive_encoder(streamOutput, ADV_ARCHIVE_NAME); +} + bool AdvancedOutput::SetupStreaming(obs_service_t *service) { int streamTrack = - config_get_int(main->Config(), "AdvOut", "TrackIndex") - 1; + config_get_int(main->Config(), "AdvOut", "TrackIndex"); if (!useStreamEncoder || (!ffmpegOutput && !obs_output_active(fileOutput))) { @@ -1589,7 +1743,7 @@ bool AdvancedOutput::SetupStreaming(obs_service_t *service) streamAudioEnc = obs_audio_encoder_create( id, "alt_audio_enc", nullptr, - streamTrack, nullptr); + streamTrack - 1, nullptr); if (!streamAudioEnc) return false; @@ -1606,6 +1760,7 @@ bool AdvancedOutput::SetupStreaming(obs_service_t *service) obs_output_set_video_encoder(streamOutput, h264Streaming); obs_output_set_audio_encoder(streamOutput, streamAudioEnc, 0); + return true; } @@ -1648,6 +1803,8 @@ bool AdvancedOutput::StartStreaming(obs_service_t *service) obs_output_set_reconnect_settings(streamOutput, maxRetries, retryDelay); + SetupVodTrack(service); + if (obs_output_start(streamOutput)) { return true; } @@ -1798,9 +1955,15 @@ bool AdvancedOutput::StartReplayBuffer() } if (!obs_output_start(replayBuffer)) { + QString error_reason; + const char *error = obs_output_get_last_error(replayBuffer); + if (error) + error_reason = QT_UTF8(error); + else + error_reason = QTStr("Output.StartFailedGeneric"); QMessageBox::critical(main, QTStr("Output.StartRecordingFailed"), - QTStr("Output.StartFailedGeneric")); + error_reason); return false; } diff --git a/UI/window-basic-main-outputs.hpp b/UI/window-basic-main-outputs.hpp index 5f9f0bd..e928de4 100644 --- a/UI/window-basic-main-outputs.hpp +++ b/UI/window-basic-main-outputs.hpp @@ -33,6 +33,7 @@ struct BasicOutputHandler { OBSSignal streamStopping; OBSSignal recordStopping; OBSSignal replayBufferStopping; + OBSSignal replayBufferSaved; inline BasicOutputHandler(OBSBasic *main_); diff --git a/UI/window-basic-main-profiles.cpp b/UI/window-basic-main-profiles.cpp index b833da0..86e9631 100644 --- a/UI/window-basic-main-profiles.cpp +++ b/UI/window-basic-main-profiles.cpp @@ -22,6 +22,7 @@ #include #include #include "window-basic-main.hpp" +#include "window-basic-auto-config.hpp" #include "window-namedialog.hpp" #include "qt-wrappers.hpp" @@ -93,14 +94,25 @@ static bool ProfileExists(const char *findName) static bool GetProfileName(QWidget *parent, std::string &name, std::string &file, const char *title, - const char *text, const char *oldName = nullptr) + const char *text, const bool showWizard, + bool &wizardChecked, const char *oldName = nullptr) { char path[512]; int ret; for (;;) { - bool success = NameDialog::AskForName(parent, title, text, name, - QT_UTF8(oldName)); + bool success = false; + + if (showWizard) { + success = NameDialog::AskForNameWithOption( + parent, title, text, name, + QTStr("AddProfile.WizardCheckbox"), + wizardChecked, QT_UTF8(oldName)); + } else { + success = NameDialog::AskForName( + parent, title, text, name, QT_UTF8(oldName)); + } + if (!success) { return false; } @@ -193,9 +205,18 @@ bool OBSBasic::AddProfile(bool create_new, const char *title, const char *text, std::string newPath; ConfigFile config; - if (!GetProfileName(this, newName, newDir, title, text, init_text)) + bool showWizardChecked = config_get_bool(App()->GlobalConfig(), "Basic", + "ConfigOnNewProfile"); + + if (!GetProfileName(this, newName, newDir, title, text, create_new, + showWizardChecked, init_text)) return false; + if (create_new) { + config_set_bool(App()->GlobalConfig(), "Basic", + "ConfigOnNewProfile", showWizardChecked); + } + std::string curDir = config_get_string(App()->GlobalConfig(), "Basic", "ProfileDir"); @@ -258,6 +279,15 @@ bool OBSBasic::AddProfile(bool create_new, const char *title, const char *text, config_save_safe(App()->GlobalConfig(), "tmp", nullptr); UpdateTitleBar(); + // Run auto configuration setup wizard when a new profile is made to assist + // setting up blank settings + if (create_new && showWizardChecked) { + AutoConfig wizard(this); + wizard.setModal(true); + wizard.show(); + wizard.exec(); + } + if (api) { api->on_event(OBS_FRONTEND_EVENT_PROFILE_LIST_CHANGED); api->on_event(OBS_FRONTEND_EVENT_PROFILE_CHANGED); diff --git a/UI/window-basic-main-transitions.cpp b/UI/window-basic-main-transitions.cpp index 98b43cd..8b491a8 100644 --- a/UI/window-basic-main-transitions.cpp +++ b/UI/window-basic-main-transitions.cpp @@ -617,37 +617,35 @@ void OBSBasic::RenameTransition() QTStr("TransitionNameDlg.Text"), name, placeHolderText); - if (accepted) { - if (name.empty()) { - OBSMessageBox::warning(this, - QTStr("NoNameEntered.Title"), - QTStr("NoNameEntered.Text")); - RenameTransition(); - return; - } + if (!accepted) + return; + if (name.empty()) { + OBSMessageBox::warning(this, QTStr("NoNameEntered.Title"), + QTStr("NoNameEntered.Text")); + RenameTransition(); + return; + } - source = FindTransition(name.c_str()); - if (source) { - OBSMessageBox::warning(this, QTStr("NameExists.Title"), - QTStr("NameExists.Text")); + source = FindTransition(name.c_str()); + if (source) { + OBSMessageBox::warning(this, QTStr("NameExists.Title"), + QTStr("NameExists.Text")); - RenameTransition(); - return; - } + RenameTransition(); + return; + } - obs_source_set_name(transition, name.c_str()); - int idx = ui->transitions->findData(variant); - if (idx != -1) { - ui->transitions->setItemText(idx, - QT_UTF8(name.c_str())); + obs_source_set_name(transition, name.c_str()); + int idx = ui->transitions->findData(variant); + if (idx != -1) { + ui->transitions->setItemText(idx, QT_UTF8(name.c_str())); - if (api) - api->on_event( - OBS_FRONTEND_EVENT_TRANSITION_LIST_CHANGED); + if (api) + api->on_event( + OBS_FRONTEND_EVENT_TRANSITION_LIST_CHANGED); - ClearQuickTransitionWidgets(); - RefreshQuickTransitions(); - } + ClearQuickTransitionWidgets(); + RefreshQuickTransitions(); } } diff --git a/UI/window-basic-main.cpp b/UI/window-basic-main.cpp index 3ccf287..6ea33d7 100644 --- a/UI/window-basic-main.cpp +++ b/UI/window-basic-main.cpp @@ -360,8 +360,6 @@ OBSBasic::OBSBasic(QWidget *parent) QPoint curPos; - UpdateContextBar(); - //restore parent window geometry const char *geometry = config_get_string(App()->GlobalConfig(), "BasicWindow", "geometry"); @@ -1112,6 +1110,7 @@ retryScene: copyStrings.clear(); copyFiltersString = nullptr; + copyFilter = nullptr; LogScenes(); @@ -1267,6 +1266,22 @@ bool OBSBasic::InitBasicConfigDefaults() changed = true; } + /* ----------------------------------------------------- */ + /* move bitrate enforcement setting to new value */ + if (config_has_user_value(basicConfig, "SimpleOutput", + "EnforceBitrate") && + !config_has_user_value(basicConfig, "Stream1", + "IgnoreRecommended") && + !config_has_user_value(basicConfig, "Stream1", "MovedOldEnforce")) { + bool enforce = config_get_bool(basicConfig, "SimpleOutput", + "EnforceBitrate"); + config_set_bool(basicConfig, "Stream1", "IgnoreRecommended", + !enforce); + config_set_bool(basicConfig, "Stream1", "MovedOldEnforce", + true); + changed = true; + } + /* ----------------------------------------------------- */ if (changed) @@ -1276,6 +1291,9 @@ bool OBSBasic::InitBasicConfigDefaults() config_set_default_string(basicConfig, "Output", "Mode", "Simple"); + config_set_default_bool(basicConfig, "Stream1", "IgnoreRecommended", + false); + config_set_default_string(basicConfig, "SimpleOutput", "FilePath", GetDefaultVideoSavePath().c_str()); config_set_default_string(basicConfig, "SimpleOutput", "RecFormat", @@ -1284,8 +1302,6 @@ bool OBSBasic::InitBasicConfigDefaults() config_set_default_uint(basicConfig, "SimpleOutput", "ABitrate", 160); config_set_default_bool(basicConfig, "SimpleOutput", "UseAdvanced", false); - config_set_default_bool(basicConfig, "SimpleOutput", "EnforceBitrate", - true); config_set_default_string(basicConfig, "SimpleOutput", "Preset", "veryfast"); config_set_default_string(basicConfig, "SimpleOutput", "NVENCPreset", @@ -1302,6 +1318,7 @@ bool OBSBasic::InitBasicConfigDefaults() true); config_set_default_bool(basicConfig, "AdvOut", "UseRescale", false); config_set_default_uint(basicConfig, "AdvOut", "TrackIndex", 1); + config_set_default_uint(basicConfig, "AdvOut", "VodTrackIndex", 2); config_set_default_string(basicConfig, "AdvOut", "Encoder", "obs_x264"); config_set_default_string(basicConfig, "AdvOut", "RecType", "Standard"); @@ -1452,7 +1469,7 @@ bool OBSBasic::InitBasicConfig() ret = GetProfilePath(configPath, sizeof(configPath), "basic.ini"); if (ret <= 0) { - OBSErrorBox(nullptr, "Failed to get base.ini path"); + OBSErrorBox(nullptr, "Failed to get basic.ini path"); return false; } @@ -1680,6 +1697,12 @@ void OBSBasic::OBSInit() InitOBSCallbacks(); InitHotkeys(); + /* hack to prevent elgato from loading its own Qt5Network that it tries + * to ship with */ +#if defined(_WIN32) && !defined(_DEBUG) + LoadLibraryW(L"Qt5Network"); +#endif + AddExtraModulePaths(); blog(LOG_INFO, "---------------------------------"); obs_load_all_modules(); @@ -1747,17 +1770,12 @@ void OBSBasic::OBSInit() GetGlobalConfig(), "BasicWindow", "ShowSourceIcons"); ui->toggleSourceIcons->setChecked(sourceIconsVisible); - if (config_has_user_value(App()->GlobalConfig(), "BasicWindow", - "ShowContextToolbars")) { - bool visible = config_get_bool(App()->GlobalConfig(), - "BasicWindow", - "ShowContextToolbars"); - ui->toggleContextBar->setChecked(visible); - ui->contextContainer->setVisible(visible); - } else { - ui->toggleContextBar->setChecked(true); - ui->contextContainer->setVisible(true); - } + bool contextVisible = config_get_bool( + App()->GlobalConfig(), "BasicWindow", "ShowContextToolbars"); + ui->toggleContextBar->setChecked(contextVisible); + ui->contextContainer->setVisible(contextVisible); + if (contextVisible) + UpdateContextBar(true); { ProfileScope("OBSBasic::Load"); @@ -2434,7 +2452,9 @@ void OBSBasic::ClearHotkeys() obs_hotkey_pair_unregister(recordingHotkeys); obs_hotkey_pair_unregister(pauseHotkeys); obs_hotkey_pair_unregister(replayBufHotkeys); + obs_hotkey_pair_unregister(vcamHotkeys); obs_hotkey_pair_unregister(togglePreviewHotkeys); + obs_hotkey_pair_unregister(contextBarHotkeys); obs_hotkey_unregister(forceStreamingStopHotkey); obs_hotkey_unregister(togglePreviewProgramHotkey); obs_hotkey_unregister(transitionHotkey); @@ -2928,8 +2948,17 @@ static bool is_network_media_source(obs_source_t *source, const char *id) return !is_local_file; } -void OBSBasic::UpdateContextBar() +void OBSBasic::UpdateContextBarDeferred(bool force) { + QMetaObject::invokeMethod(this, "UpdateContextBar", + Qt::QueuedConnection, Q_ARG(bool, force)); +} + +void OBSBasic::UpdateContextBar(bool force) +{ + if (!ui->contextContainer->isVisible() && !force) + return; + OBSSceneItem item = GetCurrentSceneItem(); ClearContextBar(); @@ -5003,9 +5032,8 @@ void OBSBasic::CreateSourcePopupMenu(int idx, bool preview) ui->actionCopyFilters->setEnabled(true); ui->actionCopySource->setEnabled(true); - } else { - ui->actionPasteFilters->setEnabled(false); } + ui->actionPasteFilters->setEnabled(copyFiltersString && idx != -1); popup.exec(QCursor::pos()); } @@ -5597,10 +5625,19 @@ inline void OBSBasic::OnActivate() App()->IncrementSleepInhibition(); UpdateProcessPriority(); - if (trayIcon && trayIcon->isVisible()) + if (trayIcon && trayIcon->isVisible()) { +#ifdef __APPLE__ + QIcon trayMask = + QIcon(":/res/images/tray_active_macos.png"); + trayMask.setIsMask(true); + trayIcon->setIcon( + QIcon::fromTheme("obs-tray", trayMask)); +#else trayIcon->setIcon(QIcon::fromTheme( "obs-tray-active", QIcon(":/res/images/tray_active.png"))); +#endif + } } } @@ -5615,19 +5652,42 @@ inline void OBSBasic::OnDeactivate() App()->DecrementSleepInhibition(); ClearProcessPriority(); - if (trayIcon && trayIcon->isVisible()) - trayIcon->setIcon(QIcon::fromTheme( - "obs-tray", QIcon(":/res/images/obs.png"))); + if (trayIcon && trayIcon->isVisible()) { +#ifdef __APPLE__ + QIcon trayIconFile = + QIcon(":/res/images/obs_macos.png"); + trayIconFile.setIsMask(true); +#else + QIcon trayIconFile = QIcon(":/res/images/obs.png"); +#endif + trayIcon->setIcon( + QIcon::fromTheme("obs-tray", trayIconFile)); + } } else if (outputHandler->Active() && trayIcon && trayIcon->isVisible()) { - if (os_atomic_load_bool(&recording_paused)) - trayIcon->setIcon(QIcon::fromTheme( - "obs-tray-paused", - QIcon(":/res/images/obs_paused.png"))); - else - trayIcon->setIcon(QIcon::fromTheme( - "obs-tray-active", - QIcon(":/res/images/tray_active.png"))); + if (os_atomic_load_bool(&recording_paused)) { +#ifdef __APPLE__ + QIcon trayIconFile = + QIcon(":/res/images/obs_paused_macos.png"); + trayIconFile.setIsMask(true); +#else + QIcon trayIconFile = + QIcon(":/res/images/obs_paused.png"); +#endif + trayIcon->setIcon(QIcon::fromTheme("obs-tray-paused", + trayIconFile)); + } else { +#ifdef __APPLE__ + QIcon trayIconFile = + QIcon(":/res/images/tray_active_macos.png"); + trayIconFile.setIsMask(true); +#else + QIcon trayIconFile = + QIcon(":/res/images/tray_active.png"); +#endif + trayIcon->setIcon(QIcon::fromTheme("obs-tray-active", + trayIconFile)); + } } } @@ -6143,6 +6203,12 @@ void OBSBasic::ReplayBufferSave() calldata_free(&cd); } +void OBSBasic::ReplayBufferSaved() +{ + if (api) + api->on_event(OBS_FRONTEND_EVENT_REPLAY_BUFFER_SAVED); +} + void OBSBasic::ReplayBufferStop(int code) { if (!outputHandler || !outputHandler->replayBuffer) @@ -7355,6 +7421,7 @@ void OBSBasic::on_toggleContextBar_toggled(bool visible) config_set_bool(App()->GlobalConfig(), "BasicWindow", "ShowContextToolbars", visible); this->ui->contextContainer->setVisible(visible); + UpdateContextBar(true); } void OBSBasic::on_toggleStatusBar_toggled(bool visible) @@ -7507,9 +7574,14 @@ void OBSBasic::ToggleShowHide() void OBSBasic::SystemTrayInit() { +#ifdef __APPLE__ + QIcon trayIconFile = QIcon(":/res/images/obs_macos.png"); + trayIconFile.setIsMask(true); +#else + QIcon trayIconFile = QIcon(":/res/images/obs.png"); +#endif trayIcon.reset(new QSystemTrayIcon( - QIcon::fromTheme("obs-tray", QIcon(":/res/images/obs.png")), - this)); + QIcon::fromTheme("obs-tray", trayIconFile), this)); trayIcon->setToolTip("OBS Studio"); showHide = new QAction(QTStr("Basic.SystemTray.Show"), trayIcon.data()); @@ -7564,10 +7636,12 @@ void OBSBasic::IconActivated(QSystemTrayIcon::ActivationReason reason) AddProjectorMenuMonitors(studioProgramProjector, this, SLOT(OpenStudioProgramProjector())); +#ifndef __APPLE__ if (reason == QSystemTrayIcon::Trigger) { EnablePreviewDisplay(previewEnabled && !isVisible()); ToggleShowHide(); } +#endif } void OBSBasic::SysTrayNotify(const QString &text, @@ -8085,10 +8159,18 @@ void OBSBasic::PauseRecording() ui->statusbar->RecordingPaused(); - if (trayIcon && trayIcon->isVisible()) - trayIcon->setIcon(QIcon::fromTheme( - "obs-tray-paused", - QIcon(":/res/images/obs_paused.png"))); + if (trayIcon && trayIcon->isVisible()) { +#ifdef __APPLE__ + QIcon trayIconFile = + QIcon(":/res/images/obs_paused_macos.png"); + trayIconFile.setIsMask(true); +#else + QIcon trayIconFile = + QIcon(":/res/images/obs_paused.png"); +#endif + trayIcon->setIcon(QIcon::fromTheme("obs-tray-paused", + trayIconFile)); + } os_atomic_set_bool(&recording_paused, true); @@ -8116,10 +8198,18 @@ void OBSBasic::UnpauseRecording() ui->statusbar->RecordingUnpaused(); - if (trayIcon && trayIcon->isVisible()) - trayIcon->setIcon(QIcon::fromTheme( - "obs-tray-active", - QIcon(":/res/images/tray_active.png"))); + if (trayIcon && trayIcon->isVisible()) { +#ifdef __APPLE__ + QIcon trayIconFile = + QIcon(":/res/images/tray_active_macos.png"); + trayIconFile.setIsMask(true); +#else + QIcon trayIconFile = + QIcon(":/res/images/tray_active.png"); +#endif + trayIcon->setIcon(QIcon::fromTheme("obs-tray-active", + trayIconFile)); + } os_atomic_set_bool(&recording_paused, false); @@ -8203,7 +8293,6 @@ void OBSBasic::UpdateReplayBuffer(bool activate) replay.reset(new QPushButton()); replay->setAccessibleName(QTStr("Basic.Main.SaveReplay")); replay->setToolTip(QTStr("Basic.Main.SaveReplay")); - replay->setCheckable(true); replay->setChecked(false); replay->setProperty("themeID", QVariant(QStringLiteral("replayIconSmall"))); diff --git a/UI/window-basic-main.hpp b/UI/window-basic-main.hpp index 0d8cdc4..4f0ad6b 100644 --- a/UI/window-basic-main.hpp +++ b/UI/window-basic-main.hpp @@ -573,6 +573,7 @@ public slots: void ReplayBufferStart(); void ReplayBufferSave(); + void ReplayBufferSaved(); void ReplayBufferStopping(); void ReplayBufferStop(int code); @@ -839,6 +840,8 @@ public: QIcon GetGroupIcon() const; QIcon GetSceneIcon() const; + OBSWeakSource copyFilter = nullptr; + protected: virtual void closeEvent(QCloseEvent *event) override; virtual void changeEvent(QEvent *event) override; @@ -1020,7 +1023,8 @@ public slots: bool ReplayBufferActive(); void ClearContextBar(); - void UpdateContextBar(); + void UpdateContextBar(bool force = false); + void UpdateContextBarDeferred(bool force = false); public: explicit OBSBasic(QWidget *parent = 0); diff --git a/UI/window-basic-settings-stream.cpp b/UI/window-basic-settings-stream.cpp index 53231d0..2189ed5 100644 --- a/UI/window-basic-settings-stream.cpp +++ b/UI/window-basic-settings-stream.cpp @@ -71,14 +71,29 @@ void OBSBasicSettings::InitStreamPage() SLOT(UpdateServerList())); connect(ui->service, SIGNAL(currentIndexChanged(int)), this, SLOT(UpdateKeyLink())); + connect(ui->service, SIGNAL(currentIndexChanged(int)), this, + SLOT(UpdateVodTrackSetting())); + connect(ui->service, SIGNAL(currentIndexChanged(int)), this, + SLOT(UpdateServiceRecommendations())); + connect(ui->service, SIGNAL(currentIndexChanged(int)), this, + SLOT(UpdateResFPSLimits())); connect(ui->customServer, SIGNAL(textChanged(const QString &)), this, SLOT(UpdateKeyLink())); + connect(ui->ignoreRecommended, SIGNAL(clicked(bool)), this, + SLOT(DisplayEnforceWarning(bool))); + connect(ui->ignoreRecommended, SIGNAL(toggled(bool)), this, + SLOT(UpdateResFPSLimits())); connect(ui->customServer, SIGNAL(editingFinished(const QString &)), this, SLOT(UpdateKeyLink())); + connect(ui->service, SIGNAL(currentIndexChanged(int)), this, + SLOT(UpdateMoreInfoLink())); } void OBSBasicSettings::LoadStream1Settings() { + bool ignoreRecommended = + config_get_bool(main->Config(), "Stream1", "IgnoreRecommended"); + obs_service_t *service_obj = main->GetService(); const char *type = obs_service_get_type(service_obj); @@ -138,11 +153,19 @@ void OBSBasicSettings::LoadStream1Settings() obs_data_release(settings); UpdateKeyLink(); + UpdateMoreInfoLink(); + UpdateVodTrackSetting(); + UpdateServiceRecommendations(); bool streamActive = obs_frontend_streaming_active(); ui->streamPage->setEnabled(!streamActive); + ui->ignoreRecommended->setChecked(ignoreRecommended); + loading = false; + + QMetaObject::invokeMethod(this, "UpdateResFPSLimits", + Qt::QueuedConnection); } void OBSBasicSettings::SaveStream1Settings() @@ -210,6 +233,37 @@ void OBSBasicSettings::SaveStream1Settings() main->auth = auth; if (!!main->auth) main->auth->LoadUI(); + + SaveCheckBox(ui->ignoreRecommended, "Stream1", "IgnoreRecommended"); +} + +void OBSBasicSettings::UpdateMoreInfoLink() +{ + if (IsCustomService()) { + ui->moreInfoButton->hide(); + return; + } + + QString serviceName = ui->service->currentText(); + obs_properties_t *props = obs_get_service_properties("rtmp_common"); + obs_property_t *services = obs_properties_get(props, "service"); + + OBSData settings = obs_data_create(); + obs_data_release(settings); + + obs_data_set_string(settings, "service", QT_TO_UTF8(serviceName)); + obs_property_modified(services, settings); + + const char *more_info_link = + obs_data_get_string(settings, "more_info_link"); + + if (!more_info_link || (*more_info_link == '\0')) { + ui->moreInfoButton->hide(); + } else { + ui->moreInfoButton->setTargetUrl(QUrl(more_info_link)); + ui->moreInfoButton->show(); + } + obs_properties_destroy(props); } void OBSBasicSettings::UpdateKeyLink() @@ -218,9 +272,8 @@ void OBSBasicSettings::UpdateKeyLink() QString customServer = ui->customServer->text(); QString streamKeyLink; if (serviceName == "Twitch") { - streamKeyLink = - "https://www.twitch.tv/broadcast/dashboard/streamkey"; - } else if (serviceName == "YouTube / YouTube Gaming") { + streamKeyLink = "https://dashboard.twitch.tv/settings/stream"; + } else if (serviceName.startsWith("YouTube")) { streamKeyLink = "https://www.youtube.com/live_dashboard"; } else if (serviceName.startsWith("Restream.io")) { streamKeyLink = @@ -563,3 +616,445 @@ void OBSBasicSettings::on_useAuth_toggled() ui->authPwLabel->setVisible(use_auth); ui->authPwWidget->setVisible(use_auth); } + +void OBSBasicSettings::UpdateVodTrackSetting() +{ + bool enableForCustomServer = config_get_bool( + GetGlobalConfig(), "General", "EnableCustomServerVodTrack"); + bool enableVodTrack = ui->service->currentText() == "Twitch"; + bool wasEnabled = !!vodTrackCheckbox; + + if (enableForCustomServer && IsCustomService()) + enableVodTrack = true; + + if (enableVodTrack == wasEnabled) + return; + + if (!enableVodTrack) { + delete vodTrackCheckbox; + delete vodTrackContainer; + delete simpleVodTrack; + return; + } + + /* -------------------------------------- */ + /* simple output mode vod track widgets */ + + bool simpleAdv = ui->simpleOutAdvanced->isChecked(); + bool vodTrackEnabled = config_get_bool(main->Config(), "SimpleOutput", + "VodTrackEnabled"); + + simpleVodTrack = new QCheckBox(this); + simpleVodTrack->setText( + QTStr("Basic.Settings.Output.Simple.TwitchVodTrack")); + simpleVodTrack->setVisible(simpleAdv); + simpleVodTrack->setChecked(vodTrackEnabled); + + int pos; + ui->simpleStreamingLayout->getWidgetPosition(ui->simpleOutAdvanced, + &pos, nullptr); + ui->simpleStreamingLayout->insertRow(pos + 1, nullptr, simpleVodTrack); + + HookWidget(simpleVodTrack, SIGNAL(clicked(bool)), + SLOT(OutputsChanged())); + connect(ui->simpleOutAdvanced, SIGNAL(toggled(bool)), + simpleVodTrack.data(), SLOT(setVisible(bool))); + + /* -------------------------------------- */ + /* advanced output mode vod track widgets */ + + vodTrackCheckbox = new QCheckBox(this); + vodTrackCheckbox->setText( + QTStr("Basic.Settings.Output.Adv.TwitchVodTrack")); + vodTrackCheckbox->setLayoutDirection(Qt::RightToLeft); + + vodTrackContainer = new QWidget(this); + QHBoxLayout *vodTrackLayout = new QHBoxLayout(); + for (int i = 0; i < MAX_AUDIO_MIXES; i++) { + vodTrack[i] = new QRadioButton(QString::number(i + 1)); + vodTrackLayout->addWidget(vodTrack[i]); + + HookWidget(vodTrack[i], SIGNAL(clicked(bool)), + SLOT(OutputsChanged())); + } + + HookWidget(vodTrackCheckbox, SIGNAL(clicked(bool)), + SLOT(OutputsChanged())); + + vodTrackLayout->addStretch(); + vodTrackLayout->setContentsMargins(0, 0, 0, 0); + + vodTrackContainer->setLayout(vodTrackLayout); + + ui->advOutTopLayout->insertRow(2, vodTrackCheckbox, vodTrackContainer); + + vodTrackEnabled = + config_get_bool(main->Config(), "AdvOut", "VodTrackEnabled"); + vodTrackCheckbox->setChecked(vodTrackEnabled); + vodTrackContainer->setEnabled(vodTrackEnabled); + + connect(vodTrackCheckbox, SIGNAL(clicked(bool)), vodTrackContainer, + SLOT(setEnabled(bool))); + + int trackIndex = + config_get_int(main->Config(), "AdvOut", "VodTrackIndex"); + for (int i = 0; i < MAX_AUDIO_MIXES; i++) { + vodTrack[i]->setChecked((i + 1) == trackIndex); + } +} + +OBSService OBSBasicSettings::GetStream1Service() +{ + return stream1Changed ? SpawnTempService() + : OBSService(main->GetService()); +} + +void OBSBasicSettings::UpdateServiceRecommendations() +{ + bool customServer = IsCustomService(); + ui->ignoreRecommended->setVisible(!customServer); + ui->enforceSettingsLabel->setVisible(!customServer); + + OBSService service = GetStream1Service(); + + int vbitrate, abitrate; + BPtr res_list; + size_t res_count; + int fps; + + obs_service_get_max_bitrate(service, &vbitrate, &abitrate); + obs_service_get_supported_resolutions(service, &res_list, &res_count); + obs_service_get_max_fps(service, &fps); + + QString text; + +#define ENFORCE_TEXT(x) QTStr("Basic.Settings.Stream.Recommended." x) + if (vbitrate) + text += ENFORCE_TEXT("MaxVideoBitrate") + .arg(QString::number(vbitrate)); + if (abitrate) { + if (!text.isEmpty()) + text += "\n"; + text += ENFORCE_TEXT("MaxAudioBitrate") + .arg(QString::number(abitrate)); + } + if (res_count) { + if (!text.isEmpty()) + text += "\n"; + + obs_service_resolution best_res = {}; + int best_res_pixels = 0; + + for (size_t i = 0; i < res_count; i++) { + obs_service_resolution res = res_list[i]; + int res_pixels = res.cx + res.cy; + if (res_pixels > best_res_pixels) { + best_res = res; + best_res_pixels = res_pixels; + } + } + + QString res_str = + QString("%1x%2").arg(QString::number(best_res.cx), + QString::number(best_res.cy)); + text += ENFORCE_TEXT("MaxResolution").arg(res_str); + } + if (fps) { + if (!text.isEmpty()) + text += "\n"; + + text += ENFORCE_TEXT("MaxFPS").arg(QString::number(fps)); + } +#undef ENFORCE_TEXT + + ui->enforceSettingsLabel->setText(text); +} + +void OBSBasicSettings::DisplayEnforceWarning(bool checked) +{ + if (IsCustomService()) + return; + + if (!checked) { + SimpleRecordingEncoderChanged(); + return; + } + + QMessageBox::StandardButton button; + +#define ENFORCE_WARNING(x) \ + QTStr("Basic.Settings.Stream.IgnoreRecommended.Warn." x) + + button = OBSMessageBox::question(this, ENFORCE_WARNING("Title"), + ENFORCE_WARNING("Text")); +#undef ENFORCE_WARNING + + if (button == QMessageBox::No) { + QMetaObject::invokeMethod(ui->ignoreRecommended, "setChecked", + Qt::QueuedConnection, + Q_ARG(bool, false)); + return; + } + + SimpleRecordingEncoderChanged(); +} + +bool OBSBasicSettings::ResFPSValid(obs_service_resolution *res_list, + size_t res_count, int max_fps) +{ + if (!res_count && !max_fps) + return true; + + if (res_count) { + QString res = ui->outputResolution->currentText(); + bool found_res = false; + + int cx, cy; + if (sscanf(QT_TO_UTF8(res), "%dx%d", &cx, &cy) != 2) + return false; + + for (size_t i = 0; i < res_count; i++) { + if (res_list[i].cx == cx && res_list[i].cy == cy) { + found_res = true; + break; + } + } + + if (!found_res) + return false; + } + + if (max_fps) { + int fpsType = ui->fpsType->currentIndex(); + if (fpsType != 0) + return false; + + std::string fps_str = QT_TO_UTF8(ui->fpsCommon->currentText()); + float fps; + sscanf(fps_str.c_str(), "%f", &fps); + if (fps > (float)max_fps) + return false; + } + + return true; +} + +extern void set_closest_res(int &cx, int &cy, + struct obs_service_resolution *res_list, + size_t count); + +/* Checks for and updates the resolution and FPS limits of a service, if any. + * + * If the service has a resolution and/or FPS limit, this will enforce those + * limitations in the UI itself, preventing the user from selecting a + * resolution or FPS that's not supported. + * + * This is an unpleasant thing to have to do to users, but there is no other + * way to ensure that a service's restricted resolution/framerate values are + * properly enforced, otherwise users will just be confused when things aren't + * working correctly. The user can turn it off if they're partner (or if they + * want to risk getting in trouble with their service) by selecting the "Ignore + * recommended settings" option in the stream section of settings. + * + * This only affects services that have a resolution and/or framerate limit, of + * which as of this writing, and hopefully for the foreseeable future, there is + * only one. + */ +void OBSBasicSettings::UpdateResFPSLimits() +{ + if (loading) + return; + + int idx = ui->service->currentIndex(); + if (idx == -1) + return; + + bool ignoreRecommended = ui->ignoreRecommended->isChecked(); + BPtr res_list; + size_t res_count = 0; + int max_fps = 0; + + if (!IsCustomService() && !ignoreRecommended) { + OBSService service = GetStream1Service(); + obs_service_get_supported_resolutions(service, &res_list, + &res_count); + obs_service_get_max_fps(service, &max_fps); + } + + /* ------------------------------------ */ + /* Check for enforced res/FPS */ + + QString res = ui->outputResolution->currentText(); + QString fps_str; + int cx = 0, cy = 0; + double max_fpsd = (double)max_fps; + int closest_fps_index = -1; + double fpsd; + + sscanf(QT_TO_UTF8(res), "%dx%d", &cx, &cy); + + if (res_count) + set_closest_res(cx, cy, res_list, res_count); + + if (max_fps) { + int fpsType = ui->fpsType->currentIndex(); + + if (fpsType == 1) { //Integer + fpsd = (double)ui->fpsInteger->value(); + } else if (fpsType == 2) { //Fractional + fpsd = (double)ui->fpsNumerator->value() / + (double)ui->fpsDenominator->value(); + } else { //Common + sscanf(QT_TO_UTF8(ui->fpsCommon->currentText()), "%lf", + &fpsd); + } + + double closest_diff = 1000000000000.0; + + for (int i = 0; i < ui->fpsCommon->count(); i++) { + double com_fpsd; + sscanf(QT_TO_UTF8(ui->fpsCommon->itemText(i)), "%lf", + &com_fpsd); + + if (com_fpsd > max_fpsd) { + continue; + } + + double diff = fabs(com_fpsd - fpsd); + if (diff < closest_diff) { + closest_diff = diff; + closest_fps_index = i; + fps_str = ui->fpsCommon->itemText(i); + } + } + } + + QString res_str = + QString("%1x%2").arg(QString::number(cx), QString::number(cy)); + + /* ------------------------------------ */ + /* Display message box if res/FPS bad */ + + bool valid = ResFPSValid(res_list, res_count, max_fps); + + if (!valid) { + /* if the user was already on facebook with an incompatible + * resolution, assume it's an upgrade */ + if (lastServiceIdx == -1 && lastIgnoreRecommended == -1) { + ui->ignoreRecommended->setChecked(true); + ui->ignoreRecommended->setProperty("changed", true); + stream1Changed = true; + EnableApplyButton(true); + UpdateResFPSLimits(); + return; + } + + QMessageBox::StandardButton button; + +#define WARNING_VAL(x) \ + QTStr("Basic.Settings.Output.Warn.EnforceResolutionFPS." x) + + QString str; + if (res_count) + str += WARNING_VAL("Resolution").arg(res_str); + if (max_fps) { + if (!str.isEmpty()) + str += "\n"; + str += WARNING_VAL("FPS").arg(fps_str); + } + + button = OBSMessageBox::question(this, WARNING_VAL("Title"), + WARNING_VAL("Msg").arg(str)); +#undef WARNING_VAL + + if (button == QMessageBox::No) { + if (idx != lastServiceIdx) + QMetaObject::invokeMethod( + ui->service, "setCurrentIndex", + Qt::QueuedConnection, + Q_ARG(int, lastServiceIdx)); + else + QMetaObject::invokeMethod(ui->ignoreRecommended, + "setChecked", + Qt::QueuedConnection, + Q_ARG(bool, true)); + return; + } + } + + /* ------------------------------------ */ + /* Update widgets/values if switching */ + /* to/from enforced resolution/FPS */ + + ui->outputResolution->blockSignals(true); + if (res_count) { + ui->outputResolution->clear(); + ui->outputResolution->setEditable(false); + + int new_res_index = -1; + + for (size_t i = 0; i < res_count; i++) { + obs_service_resolution val = res_list[i]; + QString str = + QString("%1x%2").arg(QString::number(val.cx), + QString::number(val.cy)); + ui->outputResolution->addItem(str); + + if (val.cx == cx && val.cy == cy) + new_res_index = (int)i; + } + + ui->outputResolution->setCurrentIndex(new_res_index); + if (!valid) { + ui->outputResolution->setProperty("changed", true); + videoChanged = true; + EnableApplyButton(true); + } + } else { + QString baseRes = ui->baseResolution->currentText(); + int baseCX, baseCY; + sscanf(QT_TO_UTF8(baseRes), "%dx%d", &baseCX, &baseCY); + + if (!ui->outputResolution->isEditable()) { + RecreateOutputResolutionWidget(); + ui->outputResolution->blockSignals(true); + ResetDownscales((uint32_t)baseCX, (uint32_t)baseCY, + true); + ui->outputResolution->setCurrentText(res); + } + } + ui->outputResolution->blockSignals(false); + + if (max_fps) { + for (int i = 0; i < ui->fpsCommon->count(); i++) { + double com_fpsd; + sscanf(QT_TO_UTF8(ui->fpsCommon->itemText(i)), "%lf", + &com_fpsd); + + if (com_fpsd > max_fpsd) { + SetComboItemEnabled(ui->fpsCommon, i, false); + continue; + } + } + + ui->fpsType->setCurrentIndex(0); + ui->fpsCommon->setCurrentIndex(closest_fps_index); + if (!valid) { + ui->fpsType->setProperty("changed", true); + ui->fpsCommon->setProperty("changed", true); + videoChanged = true; + EnableApplyButton(true); + } + } else { + for (int i = 0; i < ui->fpsCommon->count(); i++) + SetComboItemEnabled(ui->fpsCommon, i, true); + } + + SetComboItemEnabled(ui->fpsType, 1, !max_fps); + SetComboItemEnabled(ui->fpsType, 2, !max_fps); + + /* ------------------------------------ */ + + lastIgnoreRecommended = (int)ignoreRecommended; + lastServiceIdx = idx; +} diff --git a/UI/window-basic-settings.cpp b/UI/window-basic-settings.cpp index fd0fb9b..6bfaa32 100644 --- a/UI/window-basic-settings.cpp +++ b/UI/window-basic-settings.cpp @@ -425,6 +425,7 @@ OBSBasicSettings::OBSBasicSettings(QWidget *parent) HookWidget(ui->useAuth, CHECK_CHANGED, STREAM1_CHANGED); HookWidget(ui->authUsername, EDIT_CHANGED, STREAM1_CHANGED); HookWidget(ui->authPw, EDIT_CHANGED, STREAM1_CHANGED); + HookWidget(ui->ignoreRecommended, CHECK_CHANGED, STREAM1_CHANGED); HookWidget(ui->outputMode, COMBO_CHANGED, OUTPUTS_CHANGED); HookWidget(ui->simpleOutputPath, EDIT_CHANGED, OUTPUTS_CHANGED); HookWidget(ui->simpleNoSpace, CHECK_CHANGED, OUTPUTS_CHANGED); @@ -433,7 +434,6 @@ OBSBasicSettings::OBSBasicSettings(QWidget *parent) HookWidget(ui->simpleOutStrEncoder, COMBO_CHANGED, OUTPUTS_CHANGED); HookWidget(ui->simpleOutputABitrate, COMBO_CHANGED, OUTPUTS_CHANGED); HookWidget(ui->simpleOutAdvanced, CHECK_CHANGED, OUTPUTS_CHANGED); - HookWidget(ui->simpleOutEnforce, CHECK_CHANGED, OUTPUTS_CHANGED); HookWidget(ui->simpleOutPreset, COMBO_CHANGED, OUTPUTS_CHANGED); HookWidget(ui->simpleOutCustom, EDIT_CHANGED, OUTPUTS_CHANGED); HookWidget(ui->simpleOutRecQuality, COMBO_CHANGED, OUTPUTS_CHANGED); @@ -451,7 +451,6 @@ OBSBasicSettings::OBSBasicSettings(QWidget *parent) HookWidget(ui->advOutTrack4, CHECK_CHANGED, OUTPUTS_CHANGED); HookWidget(ui->advOutTrack5, CHECK_CHANGED, OUTPUTS_CHANGED); HookWidget(ui->advOutTrack6, CHECK_CHANGED, OUTPUTS_CHANGED); - HookWidget(ui->advOutApplyService, CHECK_CHANGED, OUTPUTS_CHANGED); HookWidget(ui->advOutRecType, COMBO_CHANGED, OUTPUTS_CHANGED); HookWidget(ui->advOutRecPath, EDIT_CHANGED, OUTPUTS_CHANGED); HookWidget(ui->advOutNoSpace, CHECK_CHANGED, OUTPUTS_CHANGED); @@ -755,7 +754,7 @@ OBSBasicSettings::OBSBasicSettings(QWidget *parent) this, SLOT(SimpleRecordingEncoderChanged())); connect(ui->simpleOutAdvanced, SIGNAL(toggled(bool)), this, SLOT(SimpleRecordingEncoderChanged())); - connect(ui->simpleOutEnforce, SIGNAL(toggled(bool)), this, + connect(ui->ignoreRecommended, SIGNAL(toggled(bool)), this, SLOT(SimpleRecordingEncoderChanged())); connect(ui->simpleReplayBuf, SIGNAL(toggled(bool)), this, SLOT(SimpleReplayBufferChanged())); @@ -817,6 +816,56 @@ OBSBasicSettings::OBSBasicSettings(QWidget *parent) InitStreamPage(); LoadSettings(false); + ui->advOutTrack1->setAccessibleName( + QTStr("Basic.Settings.Output.Adv.Audio.Track1")); + ui->advOutTrack2->setAccessibleName( + QTStr("Basic.Settings.Output.Adv.Audio.Track2")); + ui->advOutTrack3->setAccessibleName( + QTStr("Basic.Settings.Output.Adv.Audio.Track3")); + ui->advOutTrack4->setAccessibleName( + QTStr("Basic.Settings.Output.Adv.Audio.Track4")); + ui->advOutTrack5->setAccessibleName( + QTStr("Basic.Settings.Output.Adv.Audio.Track5")); + ui->advOutTrack6->setAccessibleName( + QTStr("Basic.Settings.Output.Adv.Audio.Track6")); + + ui->advOutRecTrack1->setAccessibleName( + QTStr("Basic.Settings.Output.Adv.Audio.Track1")); + ui->advOutRecTrack2->setAccessibleName( + QTStr("Basic.Settings.Output.Adv.Audio.Track2")); + ui->advOutRecTrack3->setAccessibleName( + QTStr("Basic.Settings.Output.Adv.Audio.Track3")); + ui->advOutRecTrack4->setAccessibleName( + QTStr("Basic.Settings.Output.Adv.Audio.Track4")); + ui->advOutRecTrack5->setAccessibleName( + QTStr("Basic.Settings.Output.Adv.Audio.Track5")); + ui->advOutRecTrack6->setAccessibleName( + QTStr("Basic.Settings.Output.Adv.Audio.Track6")); + + ui->advOutFFTrack1->setAccessibleName( + QTStr("Basic.Settings.Output.Adv.Audio.Track1")); + ui->advOutFFTrack2->setAccessibleName( + QTStr("Basic.Settings.Output.Adv.Audio.Track2")); + ui->advOutFFTrack3->setAccessibleName( + QTStr("Basic.Settings.Output.Adv.Audio.Track3")); + ui->advOutFFTrack4->setAccessibleName( + QTStr("Basic.Settings.Output.Adv.Audio.Track4")); + ui->advOutFFTrack5->setAccessibleName( + QTStr("Basic.Settings.Output.Adv.Audio.Track5")); + ui->advOutFFTrack6->setAccessibleName( + QTStr("Basic.Settings.Output.Adv.Audio.Track6")); + + ui->snappingEnabled->setAccessibleName( + QTStr("Basic.Settings.General.Snapping")); + ui->systemTrayEnabled->setAccessibleName( + QTStr("Basic.Settings.General.SysTray")); + ui->label_31->setAccessibleName( + QTStr("Basic.Settings.Output.Adv.Recording.RecType")); + ui->streamDelayEnable->setAccessibleName( + QTStr("Basic.Settings.Advanced.StreamDelay")); + ui->reconnectEnable->setAccessibleName( + QTStr("Basic.Settings.Output.Reconnect")); + // Add warning checks to advanced output recording section controls connect(ui->advOutRecTrack1, SIGNAL(clicked()), this, SLOT(AdvOutRecCheckWarnings())); @@ -1349,7 +1398,8 @@ static const double vals[] = {1.0, 1.25, (1.0 / 0.75), 1.5, (1.0 / 0.6), 1.75, static const size_t numVals = sizeof(vals) / sizeof(double); -void OBSBasicSettings::ResetDownscales(uint32_t cx, uint32_t cy) +void OBSBasicSettings::ResetDownscales(uint32_t cx, uint32_t cy, + bool ignoreAllSignals) { QString advRescale; QString advRecRescale; @@ -1364,9 +1414,17 @@ void OBSBasicSettings::ResetDownscales(uint32_t cx, uint32_t cy) advRecRescale = ui->advOutRecRescale->lineEdit()->text(); advFFRescale = ui->advOutFFRescale->lineEdit()->text(); - ui->outputResolution->blockSignals(true); + bool lockedOutputRes = !ui->outputResolution->isEditable(); - ui->outputResolution->clear(); + if (!lockedOutputRes) { + ui->outputResolution->blockSignals(true); + ui->outputResolution->clear(); + } + if (ignoreAllSignals) { + ui->advOutRescale->blockSignals(true); + ui->advOutRecRescale->blockSignals(true); + ui->advOutFFRescale->blockSignals(true); + } ui->advOutRescale->clear(); ui->advOutRecRescale->clear(); ui->advOutFFRescale->clear(); @@ -1393,7 +1451,8 @@ void OBSBasicSettings::ResetDownscales(uint32_t cx, uint32_t cy) string res = ResString(downscaleCX, downscaleCY); string outRes = ResString(outDownscaleCX, outDownscaleCY); - ui->outputResolution->addItem(res.c_str()); + if (!lockedOutputRes) + ui->outputResolution->addItem(res.c_str()); ui->advOutRescale->addItem(outRes.c_str()); ui->advOutRecRescale->addItem(outRes.c_str()); ui->advOutFFRescale->addItem(outRes.c_str()); @@ -1412,23 +1471,27 @@ void OBSBasicSettings::ResetDownscales(uint32_t cx, uint32_t cy) string res = ResString(cx, cy); - float baseAspect = float(cx) / float(cy); - float outputAspect = float(out_cx) / float(out_cy); + if (!lockedOutputRes) { + float baseAspect = float(cx) / float(cy); + float outputAspect = float(out_cx) / float(out_cy); + bool closeAspect = close_float(baseAspect, outputAspect, 0.01f); - bool closeAspect = close_float(baseAspect, outputAspect, 0.01f); - if (closeAspect) { - ui->outputResolution->lineEdit()->setText(oldOutputRes); - on_outputResolution_editTextChanged(oldOutputRes); - } else { - ui->outputResolution->lineEdit()->setText(bestScale.c_str()); - on_outputResolution_editTextChanged(bestScale.c_str()); - } + if (closeAspect) { + ui->outputResolution->lineEdit()->setText(oldOutputRes); + on_outputResolution_editTextChanged(oldOutputRes); + } else { + ui->outputResolution->lineEdit()->setText( + bestScale.c_str()); + on_outputResolution_editTextChanged(bestScale.c_str()); + } - ui->outputResolution->blockSignals(false); + ui->outputResolution->blockSignals(false); - if (!closeAspect) { - ui->outputResolution->setProperty("changed", QVariant(true)); - videoChanged = true; + if (!closeAspect) { + ui->outputResolution->setProperty("changed", + QVariant(true)); + videoChanged = true; + } } if (advRescale.isEmpty()) @@ -1441,6 +1504,12 @@ void OBSBasicSettings::ResetDownscales(uint32_t cx, uint32_t cy) ui->advOutRescale->lineEdit()->setText(advRescale); ui->advOutRecRescale->lineEdit()->setText(advRecRescale); ui->advOutFFRescale->lineEdit()->setText(advFFRescale); + + if (ignoreAllSignals) { + ui->advOutRescale->blockSignals(false); + ui->advOutRecRescale->blockSignals(false); + ui->advOutFFRescale->blockSignals(false); + } } void OBSBasicSettings::LoadDownscaleFilters() @@ -1612,8 +1681,6 @@ void OBSBasicSettings::LoadSimpleOutputSettings() config_get_uint(main->Config(), "SimpleOutput", "ABitrate"); bool advanced = config_get_bool(main->Config(), "SimpleOutput", "UseAdvanced"); - bool enforceBitrate = config_get_bool(main->Config(), "SimpleOutput", - "EnforceBitrate"); const char *preset = config_get_string(main->Config(), "SimpleOutput", "Preset"); const char *qsvPreset = @@ -1662,7 +1729,6 @@ void OBSBasicSettings::LoadSimpleOutputSettings() std::to_string(audioBitrate).c_str()); ui->simpleOutAdvanced->setChecked(advanced); - ui->simpleOutEnforce->setChecked(enforceBitrate); ui->simpleOutCustom->setText(custom); idx = ui->simpleOutRecQuality->findData(QString(recQual)); @@ -1695,10 +1761,7 @@ void OBSBasicSettings::LoadAdvOutputStreamingSettings() const char *rescaleRes = config_get_string(main->Config(), "AdvOut", "RescaleRes"); int trackIndex = config_get_int(main->Config(), "AdvOut", "TrackIndex"); - bool applyServiceSettings = config_get_bool(main->Config(), "AdvOut", - "ApplyServiceSettings"); - ui->advOutApplyService->setChecked(applyServiceSettings); ui->advOutUseRescale->setChecked(rescale); ui->advOutRescale->setEnabled(rescale); ui->advOutRescale->setCurrentText(rescaleRes); @@ -2064,6 +2127,8 @@ void OBSBasicSettings::LoadOutputSettings() if (obs_video_active()) { ui->outputMode->setEnabled(false); ui->outputModeLabel->setEnabled(false); + ui->simpleOutStrEncoderLabel->setEnabled(false); + ui->simpleOutStrEncoder->setEnabled(false); ui->simpleRecordingGroupBox->setEnabled(false); ui->replayBufferGroupBox->setEnabled(false); ui->advOutTopContainer->setEnabled(false); @@ -3302,7 +3367,6 @@ void OBSBasicSettings::SaveOutputSettings() SaveCheckBox(ui->simpleNoSpace, "SimpleOutput", "FileNameWithoutSpace"); SaveCombo(ui->simpleOutRecFormat, "SimpleOutput", "RecFormat"); SaveCheckBox(ui->simpleOutAdvanced, "SimpleOutput", "UseAdvanced"); - SaveCheckBox(ui->simpleOutEnforce, "SimpleOutput", "EnforceBitrate"); SaveComboData(ui->simpleOutPreset, "SimpleOutput", presetType); SaveEdit(ui->simpleOutCustom, "SimpleOutput", "x264Settings"); SaveComboData(ui->simpleOutRecQuality, "SimpleOutput", "RecQuality"); @@ -3314,7 +3378,6 @@ void OBSBasicSettings::SaveOutputSettings() curAdvStreamEncoder = GetComboData(ui->advOutEncoder); - SaveCheckBox(ui->advOutApplyService, "AdvOut", "ApplyServiceSettings"); SaveComboData(ui->advOutEncoder, "AdvOut", "Encoder"); SaveCheckBox(ui->advOutUseRescale, "AdvOut", "Rescale"); SaveCombo(ui->advOutRescale, "AdvOut", "RescaleRes"); @@ -3384,6 +3447,14 @@ void OBSBasicSettings::SaveOutputSettings() SaveEdit(ui->advOutTrack5Name, "AdvOut", "Track5Name"); SaveEdit(ui->advOutTrack6Name, "AdvOut", "Track6Name"); + if (vodTrackCheckbox) { + SaveCheckBox(simpleVodTrack, "SimpleOutput", "VodTrackEnabled"); + SaveCheckBox(vodTrackCheckbox, "AdvOut", "VodTrackEnabled"); + SaveTrackIndex(main->Config(), "AdvOut", "VodTrackIndex", + vodTrack[0], vodTrack[1], vodTrack[2], + vodTrack[3], vodTrack[4], vodTrack[5]); + } + SaveCheckBox(ui->advReplayBuf, "AdvOut", "RecRB"); SaveSpinBox(ui->advRBSecMax, "AdvOut", "RecRBTime"); SaveSpinBox(ui->advRBMegsMax, "AdvOut", "RecRBSize"); @@ -3867,16 +3938,22 @@ void OBSBasicSettings::on_colorFormat_currentIndexChanged(const QString &text) static bool ValidResolutions(Ui::OBSBasicSettings *ui) { QString baseRes = ui->baseResolution->lineEdit()->text(); - QString outputRes = ui->outputResolution->lineEdit()->text(); uint32_t cx, cy; - if (!ConvertResText(QT_TO_UTF8(baseRes), cx, cy) || - !ConvertResText(QT_TO_UTF8(outputRes), cx, cy)) { - + if (!ConvertResText(QT_TO_UTF8(baseRes), cx, cy)) { ui->videoMsg->setText(QTStr(INVALID_RES_STR)); return false; } + bool lockedOutRes = !ui->outputResolution->isEditable(); + if (!lockedOutRes) { + QString outRes = ui->outputResolution->lineEdit()->text(); + if (!ConvertResText(QT_TO_UTF8(outRes), cx, cy)) { + ui->videoMsg->setText(QTStr(INVALID_RES_STR)); + return false; + } + } + ui->videoMsg->setText(""); return true; } @@ -4458,9 +4535,13 @@ void OBSBasicSettings::UpdateAutomaticReplayBufferCheckboxes() switch (ui->outputMode->currentIndex()) { case 0: state = ui->simpleReplayBuf->isChecked(); + ui->simpleReplayBuf->setEnabled( + !obs_frontend_replay_buffer_active()); break; case 1: state = ui->advReplayBuf->isChecked(); + ui->advReplayBuf->setEnabled( + !obs_frontend_replay_buffer_active()); break; } ui->replayWhileStreaming->setEnabled(state); @@ -4589,15 +4670,8 @@ void OBSBasicSettings::SimpleRecordingEncoderChanged() { QString qual = ui->simpleOutRecQuality->currentData().toString(); QString warning; - bool advanced = ui->simpleOutAdvanced->isChecked(); - bool enforceBitrate = ui->simpleOutEnforce->isChecked() || !advanced; - OBSService service; - - if (stream1Changed) { - service = SpawnTempService(); - } else { - service = main->GetService(); - } + bool enforceBitrate = !ui->ignoreRecommended->isChecked(); + OBSService service = GetStream1Service(); delete simpleOutRecWarning; @@ -4851,3 +4925,34 @@ int OBSBasicSettings::CurrentFLVTrack() return 0; } + +/* Using setEditable(true) on a QComboBox when there's a custom style in use + * does not work properly, so instead completely recreate the widget, which + * seems to work fine. */ +void OBSBasicSettings::RecreateOutputResolutionWidget() +{ + QSizePolicy sizePolicy = ui->outputResolution->sizePolicy(); + bool changed = WidgetChanged(ui->outputResolution); + + delete ui->outputResolution; + ui->outputResolution = new QComboBox(ui->videoPage); + ui->outputResolution->setObjectName( + QString::fromUtf8("outputResolution")); + ui->outputResolution->setSizePolicy(sizePolicy); + ui->outputResolution->setEditable(true); + ui->outputResolution->setProperty("changed", changed); + ui->outputResLabel->setBuddy(ui->outputResolution); + + ui->outputResLayout->insertWidget(0, ui->outputResolution); + + QWidget::setTabOrder(ui->baseResolution, ui->outputResolution); + QWidget::setTabOrder(ui->outputResolution, ui->downscaleFilter); + + HookWidget(ui->outputResolution, CBEDIT_CHANGED, VIDEO_RES); + + connect(ui->outputResolution, &QComboBox::editTextChanged, this, + &OBSBasicSettings::on_outputResolution_editTextChanged); + + ui->outputResolution->lineEdit()->setValidator( + ui->baseResolution->lineEdit()->validator()); +} diff --git a/UI/window-basic-settings.hpp b/UI/window-basic-settings.hpp index 51179a2..4b5d352 100644 --- a/UI/window-basic-settings.hpp +++ b/UI/window-basic-settings.hpp @@ -32,6 +32,7 @@ class OBSBasic; class QAbstractButton; +class QRadioButton; class QComboBox; class QCheckBox; class QLabel; @@ -121,6 +122,8 @@ private: int channelIndex = 0; int lastSimpleRecQualityIdx = 0; + int lastServiceIdx = -1; + int lastIgnoreRecommended = -1; int lastChannelSetupIdx = 0; OBSFFFormatDesc formats; @@ -156,6 +159,12 @@ private: uint32_t outputCX = 0; uint32_t outputCY = 0; + QPointer simpleVodTrack; + + QPointer vodTrackCheckbox; + QPointer vodTrackContainer; + QPointer vodTrack[MAX_AUDIO_MIXES]; + void SaveCombo(QComboBox *widget, const char *section, const char *value); void SaveComboData(QComboBox *widget, const char *section, @@ -170,6 +179,11 @@ private: void SaveEncoder(QComboBox *combo, const char *section, const char *value); + bool ResFPSValid(obs_service_resolution *res_list, size_t res_count, + int max_fps); + void ClosestResFPS(obs_service_resolution *res_list, size_t res_count, + int max_fps, int &new_cx, int &new_cy, int &new_fps); + inline bool Changed() const { return generalChanged || outputsChanged || stream1Changed || @@ -239,6 +253,12 @@ private: private slots: void UpdateServerList(); void UpdateKeyLink(); + void UpdateVodTrackSetting(); + void UpdateServiceRecommendations(); + void RecreateOutputResolutionWidget(); + void UpdateResFPSLimits(); + void UpdateMoreInfoLink(); + void DisplayEnforceWarning(bool checked); void on_show_clicked(); void on_authPwShow_clicked(); void on_connectAccount_clicked(); @@ -266,7 +286,8 @@ private: /* video */ void LoadRendererList(); - void ResetDownscales(uint32_t cx, uint32_t cy); + void ResetDownscales(uint32_t cx, uint32_t cy, + bool ignoreAllSignals = false); void LoadDownscaleFilters(); void LoadResolutionLists(); void LoadFPSData(); @@ -309,6 +330,8 @@ private: int CurrentFLVTrack(); + OBSService GetStream1Service(); + private slots: void on_theme_activated(int idx); diff --git a/UI/window-basic-stats.cpp b/UI/window-basic-stats.cpp index 808a69f..90995ec 100644 --- a/UI/window-basic-stats.cpp +++ b/UI/window-basic-stats.cpp @@ -32,6 +32,22 @@ void OBSBasicStats::OBSFrontendEvent(enum obs_frontend_event event, void *ptr) } } +static QString MakeTimeLeftText(int hours, int minutes) +{ + return QString::asprintf("%d %s, %d %s", hours, + QT_TO_UTF8(QTStr("Hours")), minutes, + QT_TO_UTF8(QTStr("Minutes"))); +} + +static QString MakeMissedFramesText(uint32_t total_lagged, + uint32_t total_rendered, long double num) +{ + return QString("%1 / %2 (%3%)") + .arg(QString::number(total_lagged), + QString::number(total_rendered), + QString::number(num, 'f', 1)); +} + OBSBasicStats::OBSBasicStats(QWidget *parent, bool closeable) : QWidget(parent), cpu_info(os_cpu_usage_info_start()), @@ -65,6 +81,10 @@ OBSBasicStats::OBSBasicStats(QWidget *parent, bool closeable) recordTimeLeft = new QLabel(this); memUsage = new QLabel(this); + QString str = MakeTimeLeftText(99999, 59); + int textWidth = recordTimeLeft->fontMetrics().boundingRect(str).width(); + recordTimeLeft->setMinimumWidth(textWidth); + newStat("CPUUsage", cpuUsage, 0); newStat("HDDSpaceAvailable", hddSpace, 0); newStat("DiskFullIn", recordTimeLeft, 0); @@ -74,6 +94,11 @@ OBSBasicStats::OBSBasicStats(QWidget *parent, bool closeable) renderTime = new QLabel(this); skippedFrames = new QLabel(this); missedFrames = new QLabel(this); + + str = MakeMissedFramesText(999999, 999999, 99.99); + textWidth = missedFrames->fontMetrics().boundingRect(str).width(); + missedFrames->setMinimumWidth(textWidth); + row = 0; newStatBare("FPS", fps, 2); @@ -145,7 +170,12 @@ OBSBasicStats::OBSBasicStats(QWidget *parent, bool closeable) resize(800, 280); setWindowTitle(QTStr("Basic.Stats")); +#ifdef __APPLE__ + setWindowIcon( + QIcon::fromTheme("obs", QIcon(":/res/images/obs_256x256.png"))); +#else setWindowIcon(QIcon::fromTheme("obs", QIcon(":/res/images/obs.png"))); +#endif setWindowModality(Qt::NonModal); setAttribute(Qt::WA_DeleteOnClose, true); @@ -388,10 +418,7 @@ void OBSBasicStats::Update() : 0.0l; num *= 100.0l; - str = QString("%1 / %2 (%3%)") - .arg(QString::number(total_lagged), - QString::number(total_rendered), - QString::number(num, 'f', 1)); + str = MakeMissedFramesText(total_lagged, total_rendered, num); missedFrames->setText(str); if (num > 5.0l) @@ -445,9 +472,7 @@ void OBSBasicStats::RecordingTimeLeft() int minutes = totalMinutes % 60; int hours = totalMinutes / 60; - QString text = QString::asprintf("%d %s, %d %s", hours, - QT_TO_UTF8(QTStr("Hours")), minutes, - QT_TO_UTF8(QTStr("Minutes"))); + QString text = MakeTimeLeftText(hours, minutes); recordTimeLeft->setText(text); recordTimeLeft->setMinimumWidth(recordTimeLeft->width()); } diff --git a/UI/window-basic-status-bar.cpp b/UI/window-basic-status-bar.cpp index e425575..a018de4 100644 --- a/UI/window-basic-status-bar.cpp +++ b/UI/window-basic-status-bar.cpp @@ -521,9 +521,8 @@ void OBSBasicStatusBar::RecordingStopped() void OBSBasicStatusBar::RecordingPaused() { - QString text = QStringLiteral("REC: PAUSED"); + QString text = recordTime->text() + QStringLiteral(" (PAUSED)"); recordTime->setText(text); - recordTime->setMinimumWidth(recordTime->width()); if (recordOutput) { recordIcon->setPixmap(recordingPausePixmap); diff --git a/UI/window-importer.cpp b/UI/window-importer.cpp index 8f466e8..f8626c2 100644 --- a/UI/window-importer.cpp +++ b/UI/window-importer.cpp @@ -577,11 +577,13 @@ void OBSImporter::importCollections() json11::Json::object out = res.object_items(); QString file = res["name"].string_value().c_str(); + file.replace(" ", "_"); + file.replace("/", "_"); bool safe = !CheckConfigExists(dst, file); int x = 1; while (!safe) { file = name; - file += " ("; + file += "_("; file += QString::number(x); file += ")"; @@ -593,13 +595,20 @@ void OBSImporter::importCollections() std::string save = dst; save += "/"; - save += file.replace(" ", "_").toStdString(); + save += file.toStdString(); save += ".json"; std::string out_str = json11::Json(out).dump(); - os_quick_write_utf8_file(save.c_str(), out_str.c_str(), - out_str.size(), false); + bool success = os_quick_write_utf8_file(save.c_str(), + out_str.c_str(), + out_str.size(), + false); + + blog(LOG_INFO, "Import Scene Collection: %s (%s) - %s", + name.toStdString().c_str(), + file.toStdString().c_str(), + success ? "SUCCESS" : "FAILURE"); } } diff --git a/UI/window-namedialog.cpp b/UI/window-namedialog.cpp index 395e659..a9d69d3 100644 --- a/UI/window-namedialog.cpp +++ b/UI/window-namedialog.cpp @@ -17,17 +17,37 @@ #include "window-namedialog.hpp" #include "qt-wrappers.hpp" -#include "ui_NameDialog.h" #include "obs-app.hpp" -using namespace std; +#include -NameDialog::NameDialog(QWidget *parent) - : QDialog(parent), ui(new Ui::NameDialog) +NameDialog::NameDialog(QWidget *parent) : QDialog(parent) { - ui->setupUi(this); - installEventFilter(CreateShortcutFilter()); + setModal(true); + setWindowModality(Qt::WindowModality::WindowModal); + setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); + setFixedWidth(555); + setMinimumHeight(100); + QVBoxLayout *layout = new QVBoxLayout; + setLayout(layout); + + label = new QLabel(this); + layout->addWidget(label); + label->setText("Set Text"); + + userText = new QLineEdit(this); + layout->addWidget(userText); + + checkbox = new QCheckBox(this); + layout->addWidget(checkbox); + + QDialogButtonBox *buttonbox = new QDialogButtonBox( + QDialogButtonBox::Ok | QDialogButtonBox::Cancel); + layout->addWidget(buttonbox); + buttonbox->setCenterButtons(true); + connect(buttonbox, &QDialogButtonBox::accepted, this, &QDialog::accept); + connect(buttonbox, &QDialogButtonBox::rejected, this, &QDialog::reject); } static bool IsWhitespace(char ch) @@ -35,8 +55,16 @@ static bool IsWhitespace(char ch) return ch == ' ' || ch == '\t'; } +static void CleanWhitespace(std::string &str) +{ + while (str.size() && IsWhitespace(str.back())) + str.erase(str.end() - 1); + while (str.size() && IsWhitespace(str.front())) + str.erase(str.begin()); +} + bool NameDialog::AskForName(QWidget *parent, const QString &title, - const QString &text, string &str, + const QString &text, std::string &userTextInput, const QString &placeHolder, int maxSize) { if (maxSize <= 0 || maxSize > 32767) @@ -44,22 +72,43 @@ bool NameDialog::AskForName(QWidget *parent, const QString &title, NameDialog dialog(parent); dialog.setWindowTitle(title); - dialog.setWindowFlags(dialog.windowFlags() & - ~Qt::WindowContextHelpButtonHint); - dialog.ui->label->setText(text); - dialog.ui->userText->setMaxLength(maxSize); - dialog.ui->userText->setText(placeHolder); - dialog.ui->userText->selectAll(); - bool accepted = (dialog.exec() == DialogCode::Accepted); - if (accepted) { - str = QT_TO_UTF8(dialog.ui->userText->text()); + dialog.checkbox->setHidden(true); + dialog.label->setText(text); + dialog.userText->setMaxLength(maxSize); + dialog.userText->setText(placeHolder); + dialog.userText->selectAll(); - while (str.size() && IsWhitespace(str.back())) - str.erase(str.end() - 1); - while (str.size() && IsWhitespace(str.front())) - str.erase(str.begin()); + if (dialog.exec() != DialogCode::Accepted) { + return false; + } + userTextInput = dialog.userText->text().toUtf8().constData(); + CleanWhitespace(userTextInput); + return true; +} + +bool NameDialog::AskForNameWithOption(QWidget *parent, const QString &title, + const QString &text, + std::string &userTextInput, + const QString &optionLabel, + bool &optionChecked, + const QString &placeHolder) +{ + NameDialog dialog(parent); + dialog.setWindowTitle(title); + + dialog.label->setText(text); + dialog.userText->setMaxLength(170); + dialog.userText->setText(placeHolder); + dialog.checkbox->setText(optionLabel); + dialog.checkbox->setChecked(optionChecked); + + if (dialog.exec() != DialogCode::Accepted) { + return false; } - return accepted; + userTextInput = dialog.userText->text().toUtf8().constData(); + CleanWhitespace(userTextInput); + optionChecked = dialog.checkbox->isChecked(); + return true; } diff --git a/UI/window-namedialog.hpp b/UI/window-namedialog.hpp index 0b33da2..14e9fed 100644 --- a/UI/window-namedialog.hpp +++ b/UI/window-namedialog.hpp @@ -18,22 +18,37 @@ #pragma once #include +#include +#include +#include +#include #include #include -#include "ui_NameDialog.h" - class NameDialog : public QDialog { Q_OBJECT -private: - std::unique_ptr ui; - public: NameDialog(QWidget *parent); + // Returns true if user clicks OK, false otherwise + // userTextInput returns string that user typed into dialog static bool AskForName(QWidget *parent, const QString &title, - const QString &text, std::string &str, + const QString &text, std::string &userTextInput, const QString &placeHolder = QString(""), int maxSize = 170); + + // Returns true if user clicks OK, false otherwise + // userTextInput returns string that user typed into dialog + // userOptionReturn the checkbox was ticked user accepted + static bool + AskForNameWithOption(QWidget *parent, const QString &title, + const QString &text, std::string &userTextInput, + const QString &optionLabel, bool &optionChecked, + const QString &placeHolder = QString("")); + +private: + QLabel *label; + QLineEdit *userText; + QCheckBox *checkbox; }; diff --git a/UI/window-projector.cpp b/UI/window-projector.cpp index 9e7b983..1f181aa 100644 --- a/UI/window-projector.cpp +++ b/UI/window-projector.cpp @@ -31,8 +31,12 @@ OBSProjector::OBSProjector(QWidget *widget, obs_source_t *source_, int monitor, setWindowFlags(Qt::WindowStaysOnTopHint); type = type_; - +#ifdef __APPLE__ + setWindowIcon( + QIcon::fromTheme("obs", QIcon(":/res/images/obs_256x256.png"))); +#else setWindowIcon(QIcon::fromTheme("obs", QIcon(":/res/images/obs.png"))); +#endif if (monitor == -1) resize(480, 270); diff --git a/cmake/Modules/CopyMSVCBins.cmake b/cmake/Modules/CopyMSVCBins.cmake index 504d7b1..3bebaae 100644 --- a/cmake/Modules/CopyMSVCBins.cmake +++ b/cmake/Modules/CopyMSVCBins.cmake @@ -70,6 +70,10 @@ file(GLOB FFMPEG_BIN_FILES "${FFMPEG_avcodec_INCLUDE_DIR}/../bin/libmbedcrypto*.dll" "${FFMPEG_avcodec_INCLUDE_DIR}/bin/libmbedcrypto*.dll" + "${FFMPEG_avcodec_INCLUDE_DIR}/../bin/libmbedtls*.dll" + "${FFMPEG_avcodec_INCLUDE_DIR}/bin/libmbedtls*.dll" + "${FFMPEG_avcodec_INCLUDE_DIR}/../bin/libmbedx509*.dll" + "${FFMPEG_avcodec_INCLUDE_DIR}/bin/libmbedx509*.dll" "${FFMPEG_avcodec_INCLUDE_DIR}/../bin${_bin_suffix}/libopus*.dll" "${FFMPEG_avcodec_INCLUDE_DIR}/../bin${_bin_suffix}/opus*.dll" @@ -159,6 +163,7 @@ file(GLOB QT_DEBUG_BIN_FILES "${Qt5Core_DIR}/../../../bin/Qt5Widgetsd.dll" "${Qt5Core_DIR}/../../../bin/Qt5Svgd.dll" "${Qt5Core_DIR}/../../../bin/Qt5Xmld.dll" + "${Qt5Core_DIR}/../../../bin/Qt5Networkd.dll" "${Qt5Core_DIR}/../../../bin/libGLESv2d.dll" "${Qt5Core_DIR}/../../../bin/libEGLd.dll") file(GLOB QT_DEBUG_PLAT_BIN_FILES @@ -177,6 +182,7 @@ file(GLOB QT_BIN_FILES "${Qt5Core_DIR}/../../../bin/Qt5Widgets.dll" "${Qt5Core_DIR}/../../../bin/Qt5Svg.dll" "${Qt5Core_DIR}/../../../bin/Qt5Xml.dll" + "${Qt5Core_DIR}/../../../bin/Qt5Network.dll" "${Qt5Core_DIR}/../../../bin/libGLESv2.dll" "${Qt5Core_DIR}/../../../bin/libEGL.dll") file(GLOB QT_PLAT_BIN_FILES diff --git a/cmake/Modules/FindSndio.cmake b/cmake/Modules/FindSndio.cmake new file mode 100644 index 0000000..4c20661 --- /dev/null +++ b/cmake/Modules/FindSndio.cmake @@ -0,0 +1,71 @@ +# Distributed under the OSI-approved BSD 3-Clause License. See accompanying +# file Copyright.txt or https://cmake.org/licensing for details. + +#[=======================================================================[.rst: +FindSndio +------- + +Finds the Sndio library. + +Imported Targets +^^^^^^^^^^^^^^^^ + +This module provides the following imported targets, if found: + +``Sndio::Sndio`` + The Sndio library + +Result Variables +^^^^^^^^^^^^^^^^ + +This will define the following variables: + +``Sndio_FOUND`` + True if the system has the Sndio library. +``Sndio_VERSION`` + The version of the Sndio library which was found. +``Sndio_INCLUDE_DIRS`` + Include directories needed to use Sndio. +``Sndio_LIBRARIES`` + Libraries needed to link to Sndio. + +Cache Variables +^^^^^^^^^^^^^^^ + +The following cache variables may also be set: + +``Sndio_INCLUDE_DIR`` + The directory containing ``sndio.h``. +``Sndio_LIBRARY`` + The path to the Sndio library. + +#]=======================================================================] + +find_path(Sndio_INCLUDE_DIR sndio.h) +find_library(Sndio_LIBRARY sndio) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(Sndio + FOUND_VAR Sndio_FOUND + REQUIRED_VARS + Sndio_LIBRARY + Sndio_INCLUDE_DIR +) + +if(Sndio_FOUND) + set(Sndio_LIBRARIES ${Sndio_LIBRARY}) + set(Sndio_INCLUDE_DIRS ${Sndio_INCLUDE_DIR}) +endif() + +if(Sndio_FOUND AND NOT TARGET Sndio::Sndio) + add_library(Sndio::Sndio UNKNOWN IMPORTED) + set_target_properties(Sndio::Sndio PROPERTIES + IMPORTED_LOCATION "${Sndio_LIBRARY}" + INTERFACE_INCLUDE_DIRECTORIES "${Sndio_INCLUDE_DIR}" + ) +endif() + +mark_as_advanced( + Sndio_INCLUDE_DIR + Sndio_LIBRARY +) diff --git a/deps/CMakeLists.txt b/deps/CMakeLists.txt index 333dc6a..886241e 100644 --- a/deps/CMakeLists.txt +++ b/deps/CMakeLists.txt @@ -19,9 +19,7 @@ if(WIN32) add_subdirectory(lzma) endif() -if(BUILD_CAPTIONS) - add_subdirectory(libcaption) -endif() +add_subdirectory(libcaption) find_package(Jansson 2.5 QUIET) diff --git a/deps/json11/json11.cpp b/deps/json11/json11.cpp index 9647846..88024e9 100644 --- a/deps/json11/json11.cpp +++ b/deps/json11/json11.cpp @@ -441,9 +441,9 @@ struct JsonParser final { */ char get_next_token() { consume_garbage(); - if (failed) return (char)0; + if (failed) return static_cast(0); if (i == str.size()) - return fail("unexpected end of input", (char)0); + return fail("unexpected end of input", static_cast(0)); return str[i++]; } @@ -775,8 +775,10 @@ bool Json::has_shape(const shape & types, string & err) const { return false; } + const auto& obj_items = object_items(); for (auto & item : types) { - if ((*this)[item.first].type() != item.second) { + const auto it = obj_items.find(item.first); + if (it == obj_items.cend() || it->second.type() != item.second) { err = "bad type for " + item.first + " in " + dump(); return false; } diff --git a/deps/media-playback/media-playback/decode.c b/deps/media-playback/media-playback/decode.c index e5a259b..b5be5ee 100644 --- a/deps/media-playback/media-playback/decode.c +++ b/deps/media-playback/media-playback/decode.c @@ -246,14 +246,14 @@ void mp_decode_push_packet(struct mp_decode *decode, AVPacket *packet) static inline int64_t get_estimated_duration(struct mp_decode *d, int64_t last_pts) { - if (last_pts) - return d->frame_pts - last_pts; - if (d->audio) { return av_rescale_q(d->in_frame->nb_samples, (AVRational){1, d->in_frame->sample_rate}, (AVRational){1, 1000000000}); } else { + if (last_pts) + return d->frame_pts - last_pts; + if (d->last_duration) return d->last_duration; diff --git a/deps/obs-scripting/CMakeLists.txt b/deps/obs-scripting/CMakeLists.txt index a9aaa34..42558be 100644 --- a/deps/obs-scripting/CMakeLists.txt +++ b/deps/obs-scripting/CMakeLists.txt @@ -87,10 +87,6 @@ if(UI_ENABLED) include_directories(SYSTEM "${CMAKE_SOURCE_DIR}/UI/obs-frontend-api") endif() -IF(BUILD_CAPTIONS) - string(TOUPPER "${BUILD_CAPTIONS}" BUILD_CAPTIONS) -endif() - configure_file( "${CMAKE_CURRENT_SOURCE_DIR}/obs-scripting-config.h.in" "${CMAKE_CURRENT_BINARY_DIR}/obs-scripting-config.h") diff --git a/deps/obs-scripting/obs-scripting-config.h.in b/deps/obs-scripting/obs-scripting-config.h.in index 6fab8d8..4205126 100644 --- a/deps/obs-scripting/obs-scripting-config.h.in +++ b/deps/obs-scripting/obs-scripting-config.h.in @@ -21,4 +21,3 @@ #define COMPILE_LUA @LUAJIT_FOUND@ #define COMPILE_PYTHON @PYTHON_FOUND@ #define UI_ENABLED @UI_ENABLED@ -#define BUILD_CAPTIONS @BUILD_CAPTIONS@ diff --git a/deps/obs-scripting/obs-scripting-lua.c b/deps/obs-scripting/obs-scripting-lua.c index ebf6a1f..bd7e672 100644 --- a/deps/obs-scripting/obs-scripting-lua.c +++ b/deps/obs-scripting/obs-scripting-lua.c @@ -456,7 +456,7 @@ static int obs_lua_signal_handler_disconnect(lua_State *script) const char *cb_signal = calldata_string(&cb->base.extra, "signal"); - if (cb_signal && strcmp(signal, cb_signal) != 0 && + if (cb_signal && strcmp(signal, cb_signal) == 0 && handler == cb_handler) break; diff --git a/docs/sphinx/reference-frontend-api.rst b/docs/sphinx/reference-frontend-api.rst index 40f33cf..87a01b2 100644 --- a/docs/sphinx/reference-frontend-api.rst +++ b/docs/sphinx/reference-frontend-api.rst @@ -105,6 +105,10 @@ Structures/Enumerations Triggered when the replay buffer has fully stopped. + - **OBS_FRONTEND_EVENT_REPLAY_BUFFER_SAVED** + + Triggered when the replay buffer has been saved. + - **OBS_FRONTEND_EVENT_STUDIO_MODE_ENABLED** Triggered when the user has turned on studio mode. @@ -124,7 +128,7 @@ Structures/Enumerations the program is either about to load a new scene collection, or the program is about to exit. - - **OBS_FRONTEND_FINISHED_LOADING** + - **OBS_FRONTEND_EVENT_FINISHED_LOADING** Triggered when the program has finished loading. diff --git a/docs/sphinx/reference-scenes.rst b/docs/sphinx/reference-scenes.rst index f633dcb..437259f 100644 --- a/docs/sphinx/reference-scenes.rst +++ b/docs/sphinx/reference-scenes.rst @@ -101,8 +101,8 @@ Scene Item Crop Structure (obs_sceneitem_crop) Bottom crop value. -Scene Item Order Info Structure (*obs_sceneitem_order_info) ----------------------------------------------- +Scene Item Order Info Structure (\*obs_sceneitem_order_info) +------------------------------------------------------------ .. type:: struct obs_sceneitem_order_info diff --git a/libobs-d3d11/d3d11-subsystem.cpp b/libobs-d3d11/d3d11-subsystem.cpp index 45a0fe2..dce761a 100644 --- a/libobs-d3d11/d3d11-subsystem.cpp +++ b/libobs-d3d11/d3d11-subsystem.cpp @@ -2670,6 +2670,23 @@ extern "C" EXPORT uint32_t device_texture_get_shared_handle(gs_texture_t *tex) return tex2d->isShared ? tex2d->sharedHandle : GS_INVALID_HANDLE; } +extern "C" EXPORT gs_texture_t *device_texture_wrap_obj(gs_device_t *device, + void *obj) +{ + gs_texture *texture = nullptr; + try { + texture = new gs_texture_2d(device, (ID3D11Texture2D *)obj); + } catch (const HRError &error) { + blog(LOG_ERROR, "gs_texture_wrap_obj (D3D11): %s (%08lX)", + error.str, error.hr); + LogD3D11ErrorDetails(error, device); + } catch (const char *error) { + blog(LOG_ERROR, "gs_texture_wrap_obj (D3D11): %s", error); + } + + return texture; +} + int device_texture_acquire_sync(gs_texture_t *tex, uint64_t key, uint32_t ms) { gs_texture_2d *tex2d = reinterpret_cast(tex); diff --git a/libobs-d3d11/d3d11-subsystem.hpp b/libobs-d3d11/d3d11-subsystem.hpp index a2c260c..28729a5 100644 --- a/libobs-d3d11/d3d11-subsystem.hpp +++ b/libobs-d3d11/d3d11-subsystem.hpp @@ -490,6 +490,7 @@ struct gs_texture_2d : gs_texture { gs_texture_2d(gs_device_t *device, ID3D11Texture2D *nv12, uint32_t flags); gs_texture_2d(gs_device_t *device, uint32_t handle); + gs_texture_2d(gs_device_t *device, ID3D11Texture2D *obj); }; struct gs_texture_3d : gs_texture { diff --git a/libobs-d3d11/d3d11-texture2d.cpp b/libobs-d3d11/d3d11-texture2d.cpp index c249e20..975d5b3 100644 --- a/libobs-d3d11/d3d11-texture2d.cpp +++ b/libobs-d3d11/d3d11-texture2d.cpp @@ -311,3 +311,30 @@ gs_texture_2d::gs_texture_2d(gs_device_t *device, uint32_t handle) if (FAILED(hr)) throw HRError("Failed to create shader resource view", hr); } + +gs_texture_2d::gs_texture_2d(gs_device_t *device, ID3D11Texture2D *obj) + : gs_texture(device, gs_type::gs_texture_2d, GS_TEXTURE_2D) +{ + texture = obj; + + texture->GetDesc(&td); + + this->type = GS_TEXTURE_2D; + this->format = ConvertDXGITextureFormat(td.Format); + this->levels = 1; + this->device = device; + + this->width = td.Width; + this->height = td.Height; + this->dxgiFormat = td.Format; + + memset(&resourceDesc, 0, sizeof(resourceDesc)); + resourceDesc.Format = td.Format; + resourceDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; + resourceDesc.Texture2D.MipLevels = 1; + + HRESULT hr = device->device->CreateShaderResourceView( + texture, &resourceDesc, shaderRes.Assign()); + if (FAILED(hr)) + throw HRError("Failed to create shader resource view", hr); +} diff --git a/libobs-opengl/CMakeLists.txt b/libobs-opengl/CMakeLists.txt index c2fa4fd..aa25d74 100644 --- a/libobs-opengl/CMakeLists.txt +++ b/libobs-opengl/CMakeLists.txt @@ -16,10 +16,6 @@ elseif(APPLE) set(libobs-opengl_PLATFORM_SOURCES gl-cocoa.m) - set_source_files_properties(${libobs-opengl_PLATFORM_SOURCES} - PROPERTIES - LANGUAGE C) - find_library(COCOA Cocoa) include_directories(${COCOA}) mark_as_advanced(COCOA) diff --git a/libobs-winrt/winrt-capture.cpp b/libobs-winrt/winrt-capture.cpp index 431c523..f6b5788 100644 --- a/libobs-winrt/winrt-capture.cpp +++ b/libobs-winrt/winrt-capture.cpp @@ -112,7 +112,7 @@ struct winrt_capture { bool client_area; bool capture_cursor; - bool cursor_visible; + BOOL cursor_visible; gs_texture_t *texture; bool texture_written; diff --git a/libobs-winrt/winrt-capture.h b/libobs-winrt/winrt-capture.h index 67904fe..96daa1c 100644 --- a/libobs-winrt/winrt-capture.h +++ b/libobs-winrt/winrt-capture.h @@ -15,7 +15,7 @@ EXPORT struct winrt_capture *winrt_capture_init(BOOL cursor, HWND window, BOOL client_area); EXPORT void winrt_capture_free(struct winrt_capture *capture); -EXPORT BOOL winrt_capture_supported(const struct winrt_capture *capture); +EXPORT BOOL winrt_capture_active(const struct winrt_capture *capture); EXPORT void winrt_capture_show_cursor(struct winrt_capture *capture, BOOL visible); EXPORT void winrt_capture_render(struct winrt_capture *capture, diff --git a/libobs/CMakeLists.txt b/libobs/CMakeLists.txt index 3702875..3d3733f 100644 --- a/libobs/CMakeLists.txt +++ b/libobs/CMakeLists.txt @@ -11,6 +11,10 @@ if (NOT "${FFMPEG_AVCODEC_LIBRARIES}" STREQUAL "") list(REMOVE_ITEM FFMPEG_LIBRARIES ${FFMPEG_AVCODEC_LIBRARIES}) endif() +if(DEBUG_FFMPEG_MUX) + add_definitions(-DSHOW_SUBPROCESSES) +endif() + if(UNIX) if (NOT APPLE) find_package(X11 REQUIRED) @@ -139,7 +143,6 @@ elseif(APPLE) set_source_files_properties(${libobs_PLATFORM_SOURCES} PROPERTIES - LANGUAGE C COMPILE_FLAGS "-fobjc-arc") find_library(COCOA Cocoa) @@ -361,7 +364,8 @@ set(libobs_util_SOURCES util/crc32.c util/text-lookup.c util/cf-parser.c - util/profiler.c) + util/profiler.c + util/bitstream.c) set(libobs_util_HEADERS util/curl/curl-helper.h util/sse-intrin.h @@ -388,7 +392,8 @@ set(libobs_util_HEADERS util/lexer.h util/platform.h util/profiler.h - util/profiler.hpp) + util/profiler.hpp + util/bitstream.h) set(libobs_libobs_SOURCES ${libobs_PLATFORM_SOURCES} @@ -467,12 +472,10 @@ source_group("util\\Header Files" FILES ${libobs_util_HEADERS}) source_group("audio-monitoring\\Source Files" FILES ${libobs_audio_monitoring_SOURCES}) source_group("audio-monitoring\\Header Files" FILES ${libobs_audio_monitoring_HEADERS}) -if(BUILD_CAPTIONS) - include_directories(${CMAKE_SOURCE_DIR}/deps/libcaption) - set(libobs_PLATFORM_DEPS - ${libobs_PLATFORM_DEPS} - caption) -endif() +include_directories(${CMAKE_SOURCE_DIR}/deps/libcaption) +set(libobs_PLATFORM_DEPS + ${libobs_PLATFORM_DEPS} + caption) add_library(libobs SHARED ${libobs_SOURCES} ${libobs_HEADERS}) if(UNIX AND NOT APPLE) diff --git a/libobs/audio-monitoring/pulse/pulseaudio-output.c b/libobs/audio-monitoring/pulse/pulseaudio-output.c index e9cd22c..9abfcd7 100644 --- a/libobs/audio-monitoring/pulse/pulseaudio-output.c +++ b/libobs/audio-monitoring/pulse/pulseaudio-output.c @@ -183,8 +183,10 @@ static void do_stream_write(void *param) if (bytesToFill > data->bytesRemaining) bytesToFill = data->bytesRemaining; + pulseaudio_lock(); pa_stream_begin_write(data->stream, (void **)&buffer, &bytesToFill); + pulseaudio_unlock(); circlebuf_pop_front(&data->new_data, buffer, bytesToFill); @@ -331,8 +333,20 @@ skip: static void pulseaudio_stop_playback(struct audio_monitor *monitor) { if (monitor->stream) { + /* Stop the stream */ + pulseaudio_lock(); pa_stream_disconnect(monitor->stream); + pulseaudio_unlock(); + + /* Remove the callbacks, to ensure we no longer try to do anything + * with this stream object */ + pulseaudio_write_callback(monitor->stream, NULL, NULL); + pulseaudio_set_underflow_callback(monitor->stream, NULL, NULL); + + /* Unreference the stream and drop it. PA will free it when it can. */ + pulseaudio_lock(); pa_stream_unref(monitor->stream); + pulseaudio_unlock(); monitor->stream = NULL; } diff --git a/libobs/graphics/graphics-imports.c b/libobs/graphics/graphics-imports.c index 0d3c259..8259366 100644 --- a/libobs/graphics/graphics-imports.c +++ b/libobs/graphics/graphics-imports.c @@ -210,6 +210,7 @@ bool load_graphics_imports(struct gs_exports *exports, void *module, GRAPHICS_IMPORT_OPTIONAL(gs_texture_release_dc); GRAPHICS_IMPORT_OPTIONAL(device_texture_open_shared); GRAPHICS_IMPORT_OPTIONAL(device_texture_get_shared_handle); + GRAPHICS_IMPORT_OPTIONAL(device_texture_wrap_obj); GRAPHICS_IMPORT_OPTIONAL(device_texture_acquire_sync); GRAPHICS_IMPORT_OPTIONAL(device_texture_release_sync); GRAPHICS_IMPORT_OPTIONAL(device_texture_create_nv12); diff --git a/libobs/graphics/graphics-internal.h b/libobs/graphics/graphics-internal.h index 4154688..865a3f3 100644 --- a/libobs/graphics/graphics-internal.h +++ b/libobs/graphics/graphics-internal.h @@ -299,6 +299,8 @@ struct gs_exports { gs_texture_t *(*device_texture_open_shared)(gs_device_t *device, uint32_t handle); uint32_t (*device_texture_get_shared_handle)(gs_texture_t *tex); + gs_texture_t *(*device_texture_wrap_obj)(gs_device_t *device, + void *obj); int (*device_texture_acquire_sync)(gs_texture_t *tex, uint64_t key, uint32_t ms); int (*device_texture_release_sync)(gs_texture_t *tex, uint64_t key); diff --git a/libobs/graphics/graphics.c b/libobs/graphics/graphics.c index e403edb..5cc55ec 100644 --- a/libobs/graphics/graphics.c +++ b/libobs/graphics/graphics.c @@ -2885,6 +2885,18 @@ uint32_t gs_texture_get_shared_handle(gs_texture_t *tex) return GS_INVALID_HANDLE; } +gs_texture_t *gs_texture_wrap_obj(void *obj) +{ + graphics_t *graphics = thread_graphics; + if (!gs_valid("gs_texture_wrap_obj")) + return NULL; + + if (graphics->exports.device_texture_wrap_obj) + return graphics->exports.device_texture_wrap_obj( + graphics->device, obj); + return NULL; +} + int gs_texture_acquire_sync(gs_texture_t *tex, uint64_t key, uint32_t ms) { graphics_t *graphics = thread_graphics; diff --git a/libobs/graphics/graphics.h b/libobs/graphics/graphics.h index 341a55d..2746a87 100644 --- a/libobs/graphics/graphics.h +++ b/libobs/graphics/graphics.h @@ -867,6 +867,8 @@ EXPORT gs_texture_t *gs_texture_open_shared(uint32_t handle); #define GS_INVALID_HANDLE (uint32_t) - 1 EXPORT uint32_t gs_texture_get_shared_handle(gs_texture_t *tex); +EXPORT gs_texture_t *gs_texture_wrap_obj(void *obj); + #define GS_WAIT_INFINITE (uint32_t) - 1 /** diff --git a/libobs/media-io/media-remux.c b/libobs/media-io/media-remux.c index 20fbc76..94a57bd 100644 --- a/libobs/media-io/media-remux.c +++ b/libobs/media-io/media-remux.c @@ -224,6 +224,12 @@ static inline int process_packets(media_remux_job_t job, if (ret < 0) { blog(LOG_ERROR, "media_remux: Error muxing packet: %s", av_err2str(ret)); + + /* Treat "Invalid data found when processing input" and + * "Invalid argument" as non-fatal */ + if (ret == AVERROR_INVALIDDATA || ret == EINVAL) + continue; + break; } } diff --git a/libobs/obs-audio.c b/libobs/obs-audio.c index 7303df9..2f082a2 100644 --- a/libobs/obs-audio.c +++ b/libobs/obs-audio.c @@ -116,7 +116,7 @@ static bool discard_if_stopped(obs_source_t *source, size_t channels) blog(LOG_DEBUG, "doing pending stop trick: '%s'", source->context.name); #endif - return true; + return false; } for (size_t ch = 0; ch < channels; ch++) diff --git a/libobs/obs-config.h b/libobs/obs-config.h index 96d4c5c..641952a 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 0 +#define LIBOBS_API_MINOR_VER 1 /* * Increment if backward-compatible bug fix * * Reset to zero each major or minor version */ -#define LIBOBS_API_PATCH_VER 2 +#define LIBOBS_API_PATCH_VER 0 #define MAKE_SEMANTIC_VERSION(major, minor, patch) \ ((major << 24) | (minor << 16) | patch) diff --git a/libobs/obs-data.c b/libobs/obs-data.c index 20c6952..2a5d278 100644 --- a/libobs/obs-data.c +++ b/libobs/obs-data.c @@ -1762,12 +1762,12 @@ bool obs_data_item_get_default_bool(obs_data_item_t *item) obs_data_t *obs_data_item_get_default_obj(obs_data_item_t *item) { - return data_item_get_obj(item, get_item_obj); + return data_item_get_obj(item, get_item_default_obj); } obs_data_array_t *obs_data_item_get_default_array(obs_data_item_t *item) { - return data_item_get_array(item, get_item_array); + return data_item_get_array(item, get_item_default_array); } const char *obs_data_item_get_autoselect_string(obs_data_item_t *item) diff --git a/libobs/obs-internal.h b/libobs/obs-internal.h index 929a096..81a9897 100644 --- a/libobs/obs-internal.h +++ b/libobs/obs-internal.h @@ -36,6 +36,8 @@ #include "obs.h" +#include + #define NUM_TEXTURES 2 #define NUM_CHANNELS 3 #define MICROSECOND_DEN 1000000 @@ -587,6 +589,11 @@ struct audio_cb_info { void *param; }; +struct caption_cb_info { + obs_source_caption_t callback; + void *param; +}; + struct obs_source { struct obs_context_data context; struct obs_source_info info; @@ -690,6 +697,9 @@ struct obs_source { uint32_t async_convert_width[MAX_AV_PLANES]; uint32_t async_convert_height[MAX_AV_PLANES]; + pthread_mutex_t caption_cb_mutex; + DARRAY(struct caption_cb_info) caption_cb_list; + /* async video deinterlacing */ uint64_t deinterlace_offset; uint64_t deinterlace_frame_ts; @@ -977,6 +987,8 @@ struct obs_output { struct caption_text *caption_head; struct caption_text *caption_tail; + struct circlebuf caption_data; + bool valid; uint64_t active_delay_ns; diff --git a/libobs/obs-nix.c b/libobs/obs-nix.c index de039c1..382fa05 100644 --- a/libobs/obs-nix.c +++ b/libobs/obs-nix.c @@ -23,10 +23,12 @@ #include #include #include -#if defined(__FreeBSD__) +#if defined(__FreeBSD__) || defined(__OpenBSD__) #include #endif +#if !defined(__OpenBSD__) #include +#endif #include #include #if USE_XINPUT @@ -155,9 +157,10 @@ static void log_processor_info(void) dstr_free(&proc_speed); free(line); } -#elif defined(__FreeBSD__) +#elif defined(__FreeBSD__) || defined(__OpenBSD__) static void log_processor_speed(void) { +#ifndef __OpenBSD__ char *line = NULL; size_t linecap = 0; FILE *fp; @@ -187,6 +190,7 @@ static void log_processor_speed(void) fclose(fp); dstr_free(&proc_speed); free(line); +#endif } static void log_processor_name(void) @@ -218,6 +222,19 @@ static void log_processor_info(void) static void log_memory_info(void) { +#if defined(__OpenBSD__) + int mib[2]; + size_t len; + int64_t mem; + + mib[0] = CTL_HW; + mib[1] = HW_PHYSMEM64; + len = sizeof(mem); + + if (sysctl(mib, 2, &mem, &len, NULL, 0) >= 0) + blog(LOG_INFO, "Physical Memory: %" PRIi64 "MB Total", + mem / 1024 / 1024); +#else struct sysinfo info; if (sysinfo(&info) < 0) return; @@ -227,6 +244,7 @@ static void log_memory_info(void) (uint64_t)info.totalram * info.mem_unit / 1024 / 1024, ((uint64_t)info.freeram + (uint64_t)info.bufferram) * info.mem_unit / 1024 / 1024); +#endif } static void log_kernel_version(void) @@ -312,6 +330,14 @@ static void log_distribution_info(void) dstr_free(&distro); free(line); } + +static void log_desktop_session_info(void) +{ + char *session_ptr = getenv("XDG_SESSION_TYPE"); + if (session_ptr) { + blog(LOG_INFO, "Session Type: %s", session_ptr); + } +} #endif void log_system_info(void) @@ -324,6 +350,7 @@ void log_system_info(void) log_kernel_version(); #if defined(__linux__) log_distribution_info(); + log_desktop_session_info(); #endif log_x_info(); } diff --git a/libobs/obs-output.c b/libobs/obs-output.c index c37fd12..b3f9a27 100644 --- a/libobs/obs-output.c +++ b/libobs/obs-output.c @@ -21,10 +21,8 @@ #include "obs.h" #include "obs-internal.h" -#if BUILD_CAPTIONS #include #include -#endif static inline bool active(const struct obs_output *output) { @@ -227,6 +225,7 @@ void obs_output_destroy(obs_output_t *output) os_event_destroy(output->reconnect_stop_event); obs_context_data_free(&output->context); circlebuf_free(&output->delay_data); + circlebuf_free(&output->caption_data); if (output->owns_info_id) bfree((void *)output->info.id); if (output->last_error_message) @@ -267,6 +266,10 @@ bool obs_output_actual_start(obs_output_t *output) os_atomic_dec_long(&output->delay_restart_refs); output->caption_timestamp = 0; + + circlebuf_free(&output->caption_data); + circlebuf_init(&output->caption_data); + return success; } @@ -1201,13 +1204,11 @@ static inline bool has_higher_opposing_ts(struct obs_output *output, return output->highest_video_ts > packet->dts_usec; } -#if BUILD_CAPTIONS static const uint8_t nal_start[4] = {0, 0, 0, 1}; static bool add_caption(struct obs_output *output, struct encoder_packet *out) { struct encoder_packet backup = *out; - caption_frame_t cf; sei_t sei; uint8_t *data; size_t size; @@ -1224,10 +1225,62 @@ static bool add_caption(struct obs_output *output, struct encoder_packet *out) da_push_back_array(out_data, &ref, sizeof(ref)); da_push_back_array(out_data, out->data, out->size); - caption_frame_init(&cf); - caption_frame_from_text(&cf, &output->caption_head->text[0]); + if (output->caption_data.size > 0) { - sei_from_caption_frame(&sei, &cf); + cea708_t cea708; + cea708_init(&cea708, 0); // set up a new popon frame + void *caption_buf = bzalloc(3 * sizeof(uint8_t)); + + while (output->caption_data.size > 0) { + circlebuf_pop_front(&output->caption_data, caption_buf, + 3 * sizeof(uint8_t)); + + if ((((uint8_t *)caption_buf)[0] & 0x3) != 0) { + // only send cea 608 + continue; + } + + uint16_t captionData = ((uint8_t *)caption_buf)[1]; + captionData = captionData << 8; + captionData += ((uint8_t *)caption_buf)[2]; + + // padding + if (captionData == 0x8080) { + continue; + } + + if (captionData == 0) { + continue; + } + + if (!eia608_parity_varify(captionData)) { + continue; + } + + cea708_add_cc_data(&cea708, 1, + ((uint8_t *)caption_buf)[0] & 0x3, + captionData); + } + + bfree(caption_buf); + + sei_message_t *msg = + sei_message_new(sei_type_user_data_registered_itu_t_t35, + 0, CEA608_MAX_SIZE); + msg->size = cea708_render(&cea708, sei_message_data(msg), + sei_message_size(msg)); + sei_message_append(&sei, msg); + } else if (output->caption_head) { + caption_frame_t cf; + caption_frame_init(&cf); + caption_frame_from_text(&cf, &output->caption_head->text[0]); + + sei_from_caption_frame(&sei, &cf); + + struct caption_text *next = output->caption_head->next; + bfree(output->caption_head); + output->caption_head = next; + } data = malloc(sei_render_size(&sei)); size = sei_render(&sei, data); @@ -1244,12 +1297,10 @@ static bool add_caption(struct obs_output *output, struct encoder_packet *out) sei_free(&sei); - struct caption_text *next = output->caption_head->next; - bfree(output->caption_head); - output->caption_head = next; return true; } -#endif + +double last_caption_timestamp = 0; static inline void send_interleaved(struct obs_output *output) { @@ -1266,7 +1317,6 @@ static inline void send_interleaved(struct obs_output *output) if (out.type == OBS_ENCODER_VIDEO) { output->total_frames++; -#if BUILD_CAPTIONS pthread_mutex_lock(&output->caption_mutex); double frame_timestamp = @@ -1286,8 +1336,14 @@ static inline void send_interleaved(struct obs_output *output) } } + if (output->caption_data.size > 0) { + if (last_caption_timestamp < frame_timestamp) { + last_caption_timestamp = frame_timestamp; + add_caption(output, &out); + } + } + pthread_mutex_unlock(&output->caption_mutex); -#endif } output->info.encoded_packet(output->context.data, &out); @@ -2471,7 +2527,18 @@ const char *obs_output_get_id(const obs_output_t *output) : NULL; } -#if BUILD_CAPTIONS +void obs_output_caption(obs_output_t *output, + const struct obs_source_cea_708 *captions) +{ + pthread_mutex_lock(&output->caption_mutex); + for (size_t i = 0; i < captions->packets; i++) { + circlebuf_push_back(&output->caption_data, + captions->data + (i * 3), + 3 * sizeof(uint8_t)); + } + pthread_mutex_unlock(&output->caption_mutex); +} + static struct caption_text *caption_text_new(const char *text, size_t bytes, struct caption_text *tail, struct caption_text **head, @@ -2518,7 +2585,6 @@ void obs_output_output_caption_text2(obs_output_t *output, const char *text, pthread_mutex_unlock(&output->caption_mutex); } -#endif float obs_output_get_congestion(obs_output_t *output) { diff --git a/libobs/obs-service.c b/libobs/obs-service.c index 4668a14..e2fb0e8 100644 --- a/libobs/obs-service.c +++ b/libobs/obs-service.c @@ -418,3 +418,51 @@ const char *obs_service_get_output_type(const obs_service_t *service) return service->info.get_output_type(service->context.data); return NULL; } + +void obs_service_get_supported_resolutions( + const obs_service_t *service, + struct obs_service_resolution **resolutions, size_t *count) +{ + if (!obs_service_valid(service, "obs_service_supported_resolutions")) + return; + if (!obs_ptr_valid(resolutions, "obs_service_supported_resolutions")) + return; + if (!obs_ptr_valid(count, "obs_service_supported_resolutions")) + return; + + *resolutions = NULL; + *count = 0; + + if (service->info.get_supported_resolutions) + service->info.get_supported_resolutions(service->context.data, + resolutions, count); +} + +void obs_service_get_max_fps(const obs_service_t *service, int *fps) +{ + if (!obs_service_valid(service, "obs_service_get_max_fps")) + return; + if (!obs_ptr_valid(fps, "obs_service_get_max_fps")) + return; + + *fps = 0; + + if (service->info.get_max_fps) + service->info.get_max_fps(service->context.data, fps); +} + +void obs_service_get_max_bitrate(const obs_service_t *service, + int *video_bitrate, int *audio_bitrate) +{ + if (video_bitrate) + *video_bitrate = 0; + if (audio_bitrate) + *audio_bitrate = 0; + + if (!obs_service_valid(service, "obs_service_get_max_bitrate")) + return; + + if (service->info.get_max_bitrate) + service->info.get_max_bitrate(service->context.data, + video_bitrate, audio_bitrate); +} diff --git a/libobs/obs-service.h b/libobs/obs-service.h index 71f58c5..697ccb3 100644 --- a/libobs/obs-service.h +++ b/libobs/obs-service.h @@ -28,6 +28,11 @@ extern "C" { #endif +struct obs_service_resolution { + int cx; + int cy; +}; + struct obs_service_info { /* required */ const char *id; @@ -74,7 +79,13 @@ struct obs_service_info { const char *(*get_output_type)(void *data); - /* TODO: more stuff later */ + void (*get_supported_resolutions)( + void *data, struct obs_service_resolution **resolutions, + size_t *count); + void (*get_max_fps)(void *data, int *fps); + + void (*get_max_bitrate)(void *data, int *video_bitrate, + int *audio_bitrate); }; EXPORT void obs_register_service_s(const struct obs_service_info *info, diff --git a/libobs/obs-source.c b/libobs/obs-source.c index 409463d..9aea45c 100644 --- a/libobs/obs-source.c +++ b/libobs/obs-source.c @@ -31,6 +31,8 @@ #include "obs.h" #include "obs-internal.h" +static bool filter_compatible(obs_source_t *source, obs_source_t *filter); + static inline bool data_valid(const struct obs_source *source, const char *f) { return obs_source_valid(source, f) && source->context.data; @@ -182,6 +184,7 @@ static bool obs_source_init(struct obs_source *source) pthread_mutex_init_value(&source->audio_mutex); pthread_mutex_init_value(&source->audio_buf_mutex); pthread_mutex_init_value(&source->audio_cb_mutex); + pthread_mutex_init_value(&source->caption_cb_mutex); if (pthread_mutexattr_init(&attr) != 0) return false; @@ -199,6 +202,8 @@ static bool obs_source_init(struct obs_source *source) return false; if (pthread_mutex_init(&source->async_mutex, NULL) != 0) return false; + if (pthread_mutex_init(&source->caption_cb_mutex, NULL) != 0) + return false; if (is_audio_source(source) || is_composite_source(source)) allocate_audio_output_buffer(source); @@ -493,6 +498,32 @@ void obs_source_copy_filters(obs_source_t *dst, obs_source_t *src) duplicate_filters(dst, src, dst->context.private); } +static void duplicate_filter(obs_source_t *dst, obs_source_t *filter) +{ + if (!filter_compatible(dst, filter)) + return; + + char *new_name = get_new_filter_name(dst, filter->context.name); + bool enabled = obs_source_enabled(filter); + + obs_source_t *dst_filter = obs_source_duplicate(filter, new_name, true); + obs_source_set_enabled(dst_filter, enabled); + + bfree(new_name); + obs_source_filter_add(dst, dst_filter); + obs_source_release(dst_filter); +} + +void obs_source_copy_single_filter(obs_source_t *dst, obs_source_t *filter) +{ + if (!obs_source_valid(dst, "obs_source_copy_single_filter")) + return; + if (!obs_source_valid(filter, "obs_source_copy_single_filter")) + return; + + duplicate_filter(dst, filter); +} + obs_source_t *obs_source_duplicate(obs_source_t *source, const char *new_name, bool create_private) { @@ -655,6 +686,7 @@ void obs_source_destroy(struct obs_source *source) da_free(source->audio_actions); da_free(source->audio_cb_list); + da_free(source->caption_cb_list); da_free(source->async_cache); da_free(source->async_frames); da_free(source->filters); @@ -663,6 +695,7 @@ void obs_source_destroy(struct obs_source *source) pthread_mutex_destroy(&source->audio_buf_mutex); pthread_mutex_destroy(&source->audio_cb_mutex); pthread_mutex_destroy(&source->audio_mutex); + pthread_mutex_destroy(&source->caption_cb_mutex); pthread_mutex_destroy(&source->async_mutex); obs_data_release(source->private_settings); obs_context_data_free(&source->context); @@ -2870,6 +2903,51 @@ void obs_source_set_async_rotation(obs_source_t *source, long rotation) source->async_rotation = rotation; } +void obs_source_output_cea708(obs_source_t *source, + const struct obs_source_cea_708 *captions) +{ + if (!captions) { + return; + } + + pthread_mutex_lock(&source->caption_cb_mutex); + + for (size_t i = source->caption_cb_list.num; i > 0; i--) { + struct caption_cb_info info = + source->caption_cb_list.array[i - 1]; + info.callback(info.param, source, captions); + } + + pthread_mutex_unlock(&source->caption_cb_mutex); +} + +void obs_source_add_caption_callback(obs_source_t *source, + obs_source_caption_t callback, void *param) +{ + struct caption_cb_info info = {callback, param}; + + if (!obs_source_valid(source, "obs_source_add_caption_callback")) + return; + + pthread_mutex_lock(&source->caption_cb_mutex); + da_push_back(source->caption_cb_list, &info); + pthread_mutex_unlock(&source->caption_cb_mutex); +} + +void obs_source_remove_caption_callback(obs_source_t *source, + obs_source_caption_t callback, + void *param) +{ + struct caption_cb_info info = {callback, param}; + + if (!obs_source_valid(source, "obs_source_remove_caption_callback")) + return; + + pthread_mutex_lock(&source->caption_cb_mutex); + da_erase_item(source->caption_cb_list, &info); + pthread_mutex_unlock(&source->caption_cb_mutex); +} + static inline bool preload_frame_changed(obs_source_t *source, const struct obs_source_frame *in) { diff --git a/libobs/obs-source.h b/libobs/obs-source.h index 6484242..ec4194f 100644 --- a/libobs/obs-source.h +++ b/libobs/obs-source.h @@ -186,6 +186,11 @@ enum obs_media_state { */ #define OBS_SOURCE_CONTROLLABLE_MEDIA (1 << 13) +/** + * Source type provides cea708 data + */ +#define OBS_SOURCE_CEA_708 (1 << 14) + /** @} */ typedef void (*obs_source_enum_proc_t)(obs_source_t *parent, diff --git a/libobs/obs.h b/libobs/obs.h index 09ab78d..6ad9712 100644 --- a/libobs/obs.h +++ b/libobs/obs.h @@ -212,6 +212,12 @@ struct obs_source_audio { uint64_t timestamp; }; +struct obs_source_cea_708 { + const uint8_t *data; + uint32_t packets; + uint64_t timestamp; +}; + /** * Source asynchronous video output structure. Used with * obs_source_output_video to output asynchronous video. Video is buffered as @@ -1085,6 +1091,8 @@ EXPORT obs_source_t *obs_source_get_filter_by_name(obs_source_t *source, const char *name); EXPORT void obs_source_copy_filters(obs_source_t *dst, obs_source_t *src); +EXPORT void obs_source_copy_single_filter(obs_source_t *dst, + obs_source_t *filter); EXPORT bool obs_source_enabled(const obs_source_t *source); EXPORT void obs_source_set_enabled(obs_source_t *source, bool enabled); @@ -1115,6 +1123,16 @@ EXPORT void obs_source_add_audio_capture_callback( EXPORT void obs_source_remove_audio_capture_callback( obs_source_t *source, obs_source_audio_capture_t callback, void *param); +typedef void (*obs_source_caption_t)(void *param, obs_source_t *source, + const struct obs_source_cea_708 *captions); + +EXPORT void obs_source_add_caption_callback(obs_source_t *source, + obs_source_caption_t callback, + void *param); +EXPORT void obs_source_remove_caption_callback(obs_source_t *source, + obs_source_caption_t callback, + void *param); + enum obs_deinterlace_mode { OBS_DEINTERLACE_MODE_DISABLE, OBS_DEINTERLACE_MODE_DISCARD, @@ -1206,6 +1224,9 @@ EXPORT void obs_source_output_video2(obs_source_t *source, EXPORT void obs_source_set_async_rotation(obs_source_t *source, long rotation); +EXPORT void obs_source_output_cea708(obs_source_t *source, + const struct obs_source_cea_708 *captions); + /** * Preloads asynchronous video data to allow instantaneous playback * @@ -1882,13 +1903,14 @@ EXPORT uint32_t obs_output_get_height(const obs_output_t *output); EXPORT const char *obs_output_get_id(const obs_output_t *output); -#if BUILD_CAPTIONS +EXPORT void obs_output_caption(obs_output_t *output, + const struct obs_source_cea_708 *captions); + EXPORT void obs_output_output_caption_text1(obs_output_t *output, const char *text); EXPORT void obs_output_output_caption_text2(obs_output_t *output, const char *text, double display_duration); -#endif EXPORT float obs_output_get_congestion(obs_output_t *output); EXPORT int obs_output_get_connect_time_ms(obs_output_t *output); @@ -2209,6 +2231,14 @@ EXPORT void *obs_service_get_type_data(obs_service_t *service); EXPORT const char *obs_service_get_id(const obs_service_t *service); +EXPORT void obs_service_get_supported_resolutions( + const obs_service_t *service, + struct obs_service_resolution **resolutions, size_t *count); +EXPORT void obs_service_get_max_fps(const obs_service_t *service, int *fps); + +EXPORT void obs_service_get_max_bitrate(const obs_service_t *service, + int *video_bitrate, int *audio_bitrate); + /* NOTE: This function is temporary and should be removed/replaced at a later * date. */ EXPORT const char *obs_service_get_output_type(const obs_service_t *service); diff --git a/libobs/obsconfig.h.in b/libobs/obsconfig.h.in index 1a09ebe..60dc6d0 100644 --- a/libobs/obsconfig.h.in +++ b/libobs/obsconfig.h.in @@ -15,7 +15,6 @@ #define OBS_PLUGIN_DESTINATION "@OBS_PLUGIN_DESTINATION@" #define OBS_RELATIVE_PREFIX "@OBS_RELATIVE_PREFIX@" #define OBS_UNIX_STRUCTURE @OBS_UNIX_STRUCTURE@ -#define BUILD_CAPTIONS @BUILD_CAPTIONS@ #define HAVE_DBUS @HAVE_DBUS@ #define HAVE_PULSEAUDIO @HAVE_PULSEAUDIO@ #define USE_XINPUT @USE_XINPUT@ diff --git a/libobs/util/bitstream.c b/libobs/util/bitstream.c new file mode 100644 index 0000000..801e59c --- /dev/null +++ b/libobs/util/bitstream.c @@ -0,0 +1,52 @@ +#include "bitstream.h" + +#include +#include + +void bitstream_reader_init(struct bitstream_reader *r, uint8_t *data, + size_t len) +{ + memset(r, 0, sizeof(struct bitstream_reader)); + r->buf = data; + r->subPos = 0x80; + r->len = len; +} + +uint8_t bitstream_reader_read_bit(struct bitstream_reader *r) +{ + if (r->pos >= r->len) + return 0; + + uint8_t bit = (*(r->buf + r->pos) & r->subPos) == r->subPos ? 1 : 0; + + r->subPos >>= 0x1; + if (r->subPos == 0) { + r->subPos = 0x80; + r->pos++; + } + + return bit; +} + +uint8_t bitstream_reader_read_bits(struct bitstream_reader *r, int bits) +{ + uint8_t res = 0; + + for (int i = 1; i <= bits; i++) { + res <<= 1; + res |= bitstream_reader_read_bit(r); + } + + return res; +} + +uint8_t bitstream_reader_r8(struct bitstream_reader *r) +{ + return bitstream_reader_read_bits(r, 8); +} + +uint16_t bitstream_reader_r16(struct bitstream_reader *r) +{ + uint8_t b = bitstream_reader_read_bits(r, 8); + return ((uint16_t)b << 8) | bitstream_reader_read_bits(r, 8); +} diff --git a/libobs/util/bitstream.h b/libobs/util/bitstream.h new file mode 100644 index 0000000..9612c90 --- /dev/null +++ b/libobs/util/bitstream.h @@ -0,0 +1,29 @@ +#pragma once + +#include "c99defs.h" + +/* + * General programmable serialization functions. (A shared interface to + * various reading/writing to/from different inputs/outputs) + */ + +#ifdef __cplusplus +extern "C" { +#endif + +struct bitstream_reader { + uint8_t pos; + uint8_t subPos; + uint8_t *buf; + size_t len; +}; + +EXPORT void bitstream_reader_init(struct bitstream_reader *r, uint8_t *data, + size_t len); +EXPORT uint8_t bitstream_reader_read_bits(struct bitstream_reader *r, int bits); +EXPORT uint8_t bitstream_reader_r8(struct bitstream_reader *r); +EXPORT uint16_t bitstream_reader_r16(struct bitstream_reader *r); + +#ifdef __cplusplus +} +#endif diff --git a/libobs/util/pipe-windows.c b/libobs/util/pipe-windows.c index ad82479..18c1779 100644 --- a/libobs/util/pipe-windows.c +++ b/libobs/util/pipe-windows.c @@ -57,11 +57,15 @@ static inline bool create_process(const char *cmd_line, HANDLE stdin_handle, si.hStdOutput = stdout_handle; si.hStdError = stderr_handle; + DWORD flags = 0; +#ifndef SHOW_SUBPROCESSES + flags = CREATE_NO_WINDOW; +#endif + os_utf8_to_wcs_ptr(cmd_line, 0, &cmd_line_w); if (cmd_line_w) { success = !!CreateProcessW(NULL, cmd_line_w, NULL, NULL, true, - CREATE_NO_WINDOW, NULL, NULL, &si, - &pi); + flags, NULL, NULL, &si, &pi); if (success) { *process = pi.hProcess; diff --git a/libobs/util/platform-nix.c b/libobs/util/platform-nix.c index 26800d5..30acb58 100644 --- a/libobs/util/platform-nix.c +++ b/libobs/util/platform-nix.c @@ -34,14 +34,16 @@ #include #include #include -#ifdef __FreeBSD__ +#if defined(__FreeBSD__) || defined(__OpenBSD__) #include #include #include #include #include #include +#if defined(__FreeBSD__) #include +#endif #else #include #endif @@ -272,6 +274,62 @@ char *os_get_program_data_path_ptr(const char *name) return str; } +#if defined(__OpenBSD__) +// a bit modified version of https://stackoverflow.com/a/31495527 +ssize_t os_openbsd_get_executable_path(char *epath) +{ + int mib[4]; + char **argv; + size_t len; + const char *comm; + int ok = 0; + + mib[0] = CTL_KERN; + mib[1] = KERN_PROC_ARGS; + mib[2] = getpid(); + mib[3] = KERN_PROC_ARGV; + + if (sysctl(mib, 4, NULL, &len, NULL, 0) < 0) + abort(); + + if (!(argv = malloc(len))) + abort(); + + if (sysctl(mib, 4, argv, &len, NULL, 0) < 0) + abort(); + + comm = argv[0]; + + if (*comm == '/' || *comm == '.') { + if (realpath(comm, epath)) + ok = 1; + } else { + char *sp; + char *xpath = strdup(getenv("PATH")); + char *path = strtok_r(xpath, ":", &sp); + struct stat st; + + if (!xpath) + abort(); + + while (path) { + snprintf(epath, PATH_MAX, "%s/%s", path, comm); + + if (!stat(epath, &st) && (st.st_mode & S_IXUSR)) { + ok = 1; + break; + } + path = strtok_r(NULL, ":", &sp); + } + + free(xpath); + } + + free(argv); + return ok ? (ssize_t)strlen(epath) : -1; +} +#endif + char *os_get_executable_path_ptr(const char *name) { char exe[PATH_MAX]; @@ -286,6 +344,8 @@ char *os_get_executable_path_ptr(const char *name) return NULL; } count = pathlen; +#elif defined(__OpenBSD__) + ssize_t count = os_openbsd_get_executable_path(exe); #else ssize_t count = readlink("/proc/self/exe", exe, PATH_MAX - 1); if (count >= 0) { diff --git a/libobs/util/profiler.c b/libobs/util/profiler.c index 29a047f..ff815b9 100644 --- a/libobs/util/profiler.c +++ b/libobs/util/profiler.c @@ -1058,7 +1058,11 @@ bool profiler_snapshot_dump_csv_gz(const profiler_snapshot_t *snap, profiler_snapshot_dump(snap, dump_csv_gzwrite, gz); +#ifdef _WIN32 gzclose_w(gz); +#else + gzclose(gz); +#endif return true; } diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index cad1dc7..900bd8f 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -30,6 +30,7 @@ elseif(APPLE) add_subdirectory(mac-capture) add_subdirectory(mac-vth264) add_subdirectory(mac-syphon) + add_subdirectory(mac-virtualcam) add_subdirectory(decklink/mac) add_subdirectory(vlc-video) add_subdirectory(linux-jack) @@ -41,6 +42,7 @@ elseif("${CMAKE_SYSTEM_NAME}" MATCHES "Linux") add_subdirectory(linux-alsa) add_subdirectory(decklink/linux) add_subdirectory(vlc-video) + add_subdirectory(sndio) elseif("${CMAKE_SYSTEM_NAME}" MATCHES "FreeBSD") add_subdirectory(linux-capture) add_subdirectory(linux-pulseaudio) @@ -49,6 +51,10 @@ elseif("${CMAKE_SYSTEM_NAME}" MATCHES "FreeBSD") add_subdirectory(linux-alsa) add_subdirectory(vlc-video) add_subdirectory(oss-audio) + add_subdirectory(sndio) +elseif("${CMAKE_SYSTEM_NAME}" MATCHES "OpenBSD") + add_subdirectory(linux-capture) + add_subdirectory(sndio) endif() option(BUILD_BROWSER "Build browser plugin" OFF) diff --git a/plugins/coreaudio-encoder/data/locale/az-AZ.ini b/plugins/coreaudio-encoder/data/locale/az-AZ.ini new file mode 100644 index 0000000..5714721 --- /dev/null +++ b/plugins/coreaudio-encoder/data/locale/az-AZ.ini @@ -0,0 +1,6 @@ +CoreAudioAAC="CoreAudio AAC kodlayıcı" +Bitrate="Bit sürəti" +AllowHEAAC="HE-AAC-yə icazə ver" +OutputSamplerate="Çıxış nümunə sürəti" +UseInputSampleRate="Giriş (OBS) nümunə sürətini istifadə et (dəstəklənməyən bit sürətlər siyahılana bilər)" + diff --git a/plugins/coreaudio-encoder/data/locale/de-DE.ini b/plugins/coreaudio-encoder/data/locale/de-DE.ini index d29d754..3b6471e 100644 --- a/plugins/coreaudio-encoder/data/locale/de-DE.ini +++ b/plugins/coreaudio-encoder/data/locale/de-DE.ini @@ -1,6 +1,6 @@ -CoreAudioAAC="CoreAudio‐AAC‐Encoder" +CoreAudioAAC="CoreAudio-AAC-Encoder" Bitrate="Bitrate" -AllowHEAAC="HE‐AAC erlauben" -OutputSamplerate="Ausgabe‐Sample‐Rate" -UseInputSampleRate="Eingabe‐Sample‐Rate (OBS) verwenden (listet möglicherweise nicht unterstützte Bitraten auf)" +AllowHEAAC="HE-AAC erlauben" +OutputSamplerate="Ausgabe-Sample-Rate" +UseInputSampleRate="Eingabe-Sample-Rate (OBS) verwenden (listet möglicherweise nicht unterstützte Bitraten auf)" diff --git a/plugins/coreaudio-encoder/data/locale/eo-UY.ini b/plugins/coreaudio-encoder/data/locale/eo-UY.ini new file mode 100644 index 0000000..3ac1fbc --- /dev/null +++ b/plugins/coreaudio-encoder/data/locale/eo-UY.ini @@ -0,0 +1,6 @@ +CoreAudioAAC="Kodilo de AAC de CoreAudio" +Bitrate="Bitrapido" +AllowHEAAC="Permesi HE-AAC" +OutputSamplerate="Eliga pecrapico" +UseInputSampleRate="Uzi enigan (de OBS) pecrapidon (eble listigos nesubtenatajn bitrapidojn)" + diff --git a/plugins/coreaudio-encoder/data/locale/fa-IR.ini b/plugins/coreaudio-encoder/data/locale/fa-IR.ini index 688b8b1..8e4ea7f 100644 --- a/plugins/coreaudio-encoder/data/locale/fa-IR.ini +++ b/plugins/coreaudio-encoder/data/locale/fa-IR.ini @@ -2,4 +2,5 @@ CoreAudioAAC="هسته صدا کدگذاری AAC" Bitrate="نرخ بیت" AllowHEAAC="اجازه AAC با راندمان بالا" OutputSamplerate="نرخ نمونه خروجی" +UseInputSampleRate="از نرخ نمونه ورودی (OBS) استفاده کنید (ممکن است بیت های پشتیبانی نشده را لیست کند)" diff --git a/plugins/coreaudio-encoder/data/locale/ka-GE.ini b/plugins/coreaudio-encoder/data/locale/ka-GE.ini index 40d69b5..42d6d42 100644 --- a/plugins/coreaudio-encoder/data/locale/ka-GE.ini +++ b/plugins/coreaudio-encoder/data/locale/ka-GE.ini @@ -2,5 +2,5 @@ CoreAudioAAC="CoreAudio AAC გამშიფრავი" Bitrate="ბიტური სიხშირე" AllowHEAAC="HE-AAC დაშვება" OutputSamplerate="გამომავალი სიგნალის სიხშირე" -UseInputSampleRate="შემავალი (OBS) სიგნალის სიხშირის გამოყენება (შესაძლოა მოიცავდეს მხარდაუჭერელ სიხშირეებსაც)" +UseInputSampleRate="შემავალი (OBS) სიგნალის დაყოფის სიხშირე (შესაძლოა მოიცავდეს მხარდაუჭერელ სიხშირეებსაც)" diff --git a/plugins/coreaudio-encoder/data/locale/kab-KAB.ini b/plugins/coreaudio-encoder/data/locale/kab-KAB.ini new file mode 100644 index 0000000..a945f98 --- /dev/null +++ b/plugins/coreaudio-encoder/data/locale/kab-KAB.ini @@ -0,0 +1,6 @@ +CoreAudioAAC="Asettengal CoreAudio AAC" +Bitrate="Aktum" +AllowHEAAC="Sireg HE-AAC" +OutputSamplerate="Asnagar n ulemmec n tuffɣa" +UseInputSampleRate="Seqdec asnagar n ulemmec n unekcum (OBS) (yezmer ad ibeqeḍ iktumen ur nettwadhel ara)" + diff --git a/plugins/coreaudio-encoder/data/locale/ro-RO.ini b/plugins/coreaudio-encoder/data/locale/ro-RO.ini index 4cc68d9..9d074b1 100644 --- a/plugins/coreaudio-encoder/data/locale/ro-RO.ini +++ b/plugins/coreaudio-encoder/data/locale/ro-RO.ini @@ -2,5 +2,5 @@ CoreAudioAAC="Codificator AAC CoreAudio" Bitrate="Rată de biți" AllowHEAAC="Permite HE-AAC" OutputSamplerate="Rată de eșantionare a outpului" -UseInputSampleRate="Folosește rata de eșantionare a intrării OBS (poate lista rate de biți nesuportate)" +UseInputSampleRate="Folosește rata de eșantionare a inputului OBS (poate lista rate de biți nesuportate)" diff --git a/plugins/decklink/OBSVideoFrame.cpp b/plugins/decklink/OBSVideoFrame.cpp new file mode 100644 index 0000000..a064126 --- /dev/null +++ b/plugins/decklink/OBSVideoFrame.cpp @@ -0,0 +1,83 @@ +#include "OBSVideoFrame.h" + +OBSVideoFrame::OBSVideoFrame(long width, long height) +{ + this->width = width; + this->height = height; + this->rowBytes = width * 2; + this->data = new unsigned char[width * height * 2 + 1]; +} + +HRESULT OBSVideoFrame::SetFlags(BMDFrameFlags newFlags) +{ + flags = newFlags; + return S_OK; +} + +HRESULT OBSVideoFrame::SetTimecode(BMDTimecodeFormat format, + IDeckLinkTimecode *timecode) +{ + UNUSED_PARAMETER(format); + UNUSED_PARAMETER(timecode); + return 0; +} + +HRESULT +OBSVideoFrame::SetTimecodeFromComponents(BMDTimecodeFormat format, + uint8_t hours, uint8_t minutes, + uint8_t seconds, uint8_t frames, + BMDTimecodeFlags flags) +{ + UNUSED_PARAMETER(format); + UNUSED_PARAMETER(hours); + UNUSED_PARAMETER(minutes); + UNUSED_PARAMETER(seconds); + UNUSED_PARAMETER(frames); + UNUSED_PARAMETER(flags); + return 0; +} + +HRESULT OBSVideoFrame::SetAncillaryData(IDeckLinkVideoFrameAncillary *ancillary) +{ + UNUSED_PARAMETER(ancillary); + return 0; +} + +HRESULT OBSVideoFrame::SetTimecodeUserBits(BMDTimecodeFormat format, + BMDTimecodeUserBits userBits) +{ + UNUSED_PARAMETER(format); + UNUSED_PARAMETER(userBits); + return 0; +} + +long OBSVideoFrame::GetWidth() +{ + return width; +} + +long OBSVideoFrame::GetHeight() +{ + return height; +} + +long OBSVideoFrame::GetRowBytes() +{ + return rowBytes; +} + +BMDPixelFormat OBSVideoFrame::GetPixelFormat() +{ + return pixelFormat; +} + +BMDFrameFlags OBSVideoFrame::GetFlags() +{ + return flags; +} + +HRESULT OBSVideoFrame::GetBytes(void **buffer) +{ + *buffer = this->data; + return S_OK; +} diff --git a/plugins/decklink/OBSVideoFrame.h b/plugins/decklink/OBSVideoFrame.h new file mode 100644 index 0000000..934ecf0 --- /dev/null +++ b/plugins/decklink/OBSVideoFrame.h @@ -0,0 +1,76 @@ +#pragma once + +#include "platform.hpp" +#include "obs.hpp" + +class OBSVideoFrame : public IDeckLinkMutableVideoFrame { +private: + BMDFrameFlags flags; + BMDPixelFormat pixelFormat = bmdFormat8BitYUV; + + long width; + long height; + long rowBytes; + + unsigned char *data; + +public: + OBSVideoFrame(long width, long height); + + HRESULT STDMETHODCALLTYPE SetFlags(BMDFrameFlags newFlags) override; + + HRESULT STDMETHODCALLTYPE SetTimecode( + BMDTimecodeFormat format, IDeckLinkTimecode *timecode) override; + + HRESULT STDMETHODCALLTYPE SetTimecodeFromComponents( + BMDTimecodeFormat format, uint8_t hours, uint8_t minutes, + uint8_t seconds, uint8_t frames, + BMDTimecodeFlags flags) override; + + HRESULT + STDMETHODCALLTYPE + SetAncillaryData(IDeckLinkVideoFrameAncillary *ancillary) override; + + HRESULT STDMETHODCALLTYPE + SetTimecodeUserBits(BMDTimecodeFormat format, + BMDTimecodeUserBits userBits) override; + + long STDMETHODCALLTYPE GetWidth() override; + + long STDMETHODCALLTYPE GetHeight() override; + + long STDMETHODCALLTYPE GetRowBytes() override; + + BMDPixelFormat STDMETHODCALLTYPE GetPixelFormat() override; + + BMDFrameFlags STDMETHODCALLTYPE GetFlags() override; + + HRESULT STDMETHODCALLTYPE GetBytes(void **buffer) override; + + //Dummy implementations of remaining virtual methods + virtual HRESULT STDMETHODCALLTYPE + GetTimecode(/* in */ BMDTimecodeFormat format, + /* out */ IDeckLinkTimecode **timecode) override + { + UNUSED_PARAMETER(format); + UNUSED_PARAMETER(timecode); + return E_NOINTERFACE; + }; + virtual HRESULT STDMETHODCALLTYPE GetAncillaryData( + /* out */ IDeckLinkVideoFrameAncillary **ancillary) override + { + UNUSED_PARAMETER(ancillary); + return E_NOINTERFACE; + }; + + // IUnknown interface (dummy implementation) + virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, + LPVOID *ppv) override + { + UNUSED_PARAMETER(iid); + UNUSED_PARAMETER(ppv); + return E_NOINTERFACE; + } + virtual ULONG STDMETHODCALLTYPE AddRef() override { return 1; } + virtual ULONG STDMETHODCALLTYPE Release() override { return 1; } +}; diff --git a/plugins/decklink/data/locale/az-AZ.ini b/plugins/decklink/data/locale/az-AZ.ini index a3d6815..f9ba88b 100644 --- a/plugins/decklink/data/locale/az-AZ.ini +++ b/plugins/decklink/data/locale/az-AZ.ini @@ -1,2 +1,26 @@ +BlackmagicDevice="Blackmagic Cihazı" +Device="Cihaz" +Mode="Rejim" +Buffering="Bufferləməni istifadə et" +PixelFormat="Piksel formatı" +ColorSpace="Rəng boşluğu" +ColorSpace.Default="İlkin" +ColorRange="Rəng aralığı" +ColorRange.Default="İlkin" +ColorRange.Partial="Hissəli" +ColorRange.Full="Tam" +ChannelFormat="Kanal" ChannelFormat.None="Heç biri" +ChannelFormat.2_0ch="Stereo" +ChannelFormat.2_1ch="2.1 kanal" +ChannelFormat.4_0ch="4 kanal" +ChannelFormat.4_1ch="4.1 kanal" +ChannelFormat.5_1ch="5.1 kanal" +ChannelFormat.7_1ch="7.1 kanal" +DeactivateWhenNotShowing="Göstərilməyəndə deaktiv et" +AutoStart="Açılanda avtomatik başlat" +SwapFC-LFE="FC və LFE-ni dəyişdir" +SwapFC-LFE.Tooltip="Ön Mərkəz Kanalını və LFE Kanalını dəyişdir" +VideoConnection="Video Bağlantı" +AudioConnection="Səs Bağlantısı" diff --git a/plugins/decklink/data/locale/de-DE.ini b/plugins/decklink/data/locale/de-DE.ini index f3bea7c..0aff7da 100644 --- a/plugins/decklink/data/locale/de-DE.ini +++ b/plugins/decklink/data/locale/de-DE.ini @@ -1,4 +1,4 @@ -BlackmagicDevice="Blackmagic‐Gerät" +BlackmagicDevice="Blackmagic-Gerät" Device="Gerät" Mode="Modus" Buffering="Pufferung benutzen" @@ -11,16 +11,16 @@ ColorRange.Partial="Begrenzt" ColorRange.Full="Voll" ChannelFormat="Kanal" ChannelFormat.None="Keins" -ChannelFormat.2_0ch="2‐Kanal" -ChannelFormat.2_1ch="2.1‐Kanal" -ChannelFormat.4_0ch="4‐Kanal" -ChannelFormat.4_1ch="4.1‐Kanal" -ChannelFormat.5_1ch="5.1‐Kanal" -ChannelFormat.7_1ch="7.1‐Kanal" +ChannelFormat.2_0ch="2-Kanal" +ChannelFormat.2_1ch="2.1-Kanal" +ChannelFormat.4_0ch="4-Kanal" +ChannelFormat.4_1ch="4.1-Kanal" +ChannelFormat.5_1ch="5.1-Kanal" +ChannelFormat.7_1ch="7.1-Kanal" DeactivateWhenNotShowing="Deaktivieren, wenn Quelle nicht gezeigt" AutoStart="Automatisch beim Öffnen starten" SwapFC-LFE="FC und LFE tauschen" -SwapFC-LFE.Tooltip="Vorderen Front‐Center‐Kanal und LFE‐Kanal tauschen" +SwapFC-LFE.Tooltip="Vorderen Front-Center-Kanal und LFE-Kanal tauschen" VideoConnection="Videoverbindung" AudioConnection="Audioverbindung" diff --git a/plugins/decklink/data/locale/el-GR.ini b/plugins/decklink/data/locale/el-GR.ini index b4f167a..dbc52f1 100644 --- a/plugins/decklink/data/locale/el-GR.ini +++ b/plugins/decklink/data/locale/el-GR.ini @@ -3,7 +3,9 @@ Device="Συσκευή" Mode="Λειτουργία" Buffering="Χρήση ενδιάμεσης μνήμης" PixelFormat="Μορφή pixel" +ColorSpace="Χώρος Χρωμάτων" ColorSpace.Default="Προεπιλογή" +ColorRange="Εύρος Χρωμάτων" ColorRange.Default="Προεπιλογή" ColorRange.Partial="Μερική" ColorRange.Full="Πλήρης" @@ -17,4 +19,6 @@ ChannelFormat.5_1ch="5.1ch" ChannelFormat.7_1ch="7.1ch" DeactivateWhenNotShowing="Απενεργοποίηση όταν δεν εμφανίζεται" AutoStart="Αυτόματη εκκίνηση" +VideoConnection="Σύνδεση Βίντεο" +AudioConnection="Σύνδεση Ήχου" diff --git a/plugins/decklink/data/locale/eo-UY.ini b/plugins/decklink/data/locale/eo-UY.ini new file mode 100644 index 0000000..d428a9a --- /dev/null +++ b/plugins/decklink/data/locale/eo-UY.ini @@ -0,0 +1,26 @@ +BlackmagicDevice="Aparato de Blackmagic" +Device="Aparato" +Mode="Reĝimo" +Buffering="Uzi bufradon" +PixelFormat="Bildera formo" +ColorSpace="Kolorspaco" +ColorSpace.Default="Defaŭlta" +ColorRange="Kolorvasteco" +ColorRange.Default="Defaŭlta" +ColorRange.Partial="Parta" +ColorRange.Full="Plena" +ChannelFormat="Kanalo" +ChannelFormat.None="Neniu" +ChannelFormat.2_0ch="2 kanaloj" +ChannelFormat.2_1ch="2.1 kanaloj" +ChannelFormat.4_0ch="4 kanaloj" +ChannelFormat.4_1ch="4.1 kanaloj" +ChannelFormat.5_1ch="5.1 kanaloj" +ChannelFormat.7_1ch="7.1 kanaloj" +DeactivateWhenNotShowing="Malaktivigi dum nemontro" +AutoStart="Aŭtomate startigi je lanĉo" +SwapFC-LFE="Interŝanĝi FC kaj LFE" +SwapFC-LFE.Tooltip="Interŝanĝi front-centran kanalon kaj LFE-kanalon" +VideoConnection="Video-konekto" +AudioConnection="Son-konekto" + diff --git a/plugins/decklink/data/locale/et-EE.ini b/plugins/decklink/data/locale/et-EE.ini index c707d4c..05522df 100644 --- a/plugins/decklink/data/locale/et-EE.ini +++ b/plugins/decklink/data/locale/et-EE.ini @@ -3,4 +3,24 @@ Device="Seade" Mode="Režiim" Buffering="Kasutada puhverdamist" PixelFormat="Piksli formaat" +ColorSpace="Värviruum" +ColorSpace.Default="Vaikimisi" +ColorRange="Värviruumi vahemik" +ColorRange.Default="Vaikeseade" +ColorRange.Partial="Osaline" +ColorRange.Full="Täielik" +ChannelFormat="Kanal" +ChannelFormat.None="Määramata" +ChannelFormat.2_0ch="2-kanaline" +ChannelFormat.2_1ch="2.1-kanaline" +ChannelFormat.4_0ch="4-kanaline" +ChannelFormat.4_1ch="4.1-kanaline" +ChannelFormat.5_1ch="5.1-kanaline" +ChannelFormat.7_1ch="7.1-kanaline" +DeactivateWhenNotShowing="Laadi maha kui ei ole nähtav" +AutoStart="Automaatne startimine käivitamisel" +SwapFC-LFE="Vahetage FC ja LFE" +SwapFC-LFE.Tooltip="Vahetage eesmine keskkanal ja LFE kanal" +VideoConnection="Videoühendus" +AudioConnection="Audioühendus" diff --git a/plugins/decklink/data/locale/eu-ES.ini b/plugins/decklink/data/locale/eu-ES.ini index a64ec00..090b930 100644 --- a/plugins/decklink/data/locale/eu-ES.ini +++ b/plugins/decklink/data/locale/eu-ES.ini @@ -19,7 +19,6 @@ ChannelFormat.5_1ch="5.1 kanala" ChannelFormat.7_1ch="7.1 kanala" DeactivateWhenNotShowing="Desaktibatu ikusten ez denean" AutoStart="Hasi automatikoki abiatzean" -SwapFC-LFE="Aldatu FC <-> LFE" SwapFC-LFE.Tooltip="Aldatu Aurreko Kanal Zentrala eta LFE kanala (subwooferra)" VideoConnection="Bideo-konexioa" AudioConnection="Audio-konexioa" diff --git a/plugins/decklink/data/locale/fa-IR.ini b/plugins/decklink/data/locale/fa-IR.ini index 89b7ab6..95ae0ec 100644 --- a/plugins/decklink/data/locale/fa-IR.ini +++ b/plugins/decklink/data/locale/fa-IR.ini @@ -3,7 +3,9 @@ Device="دستگاه" Mode="نوع" Buffering="استفاده از بافرینگ" PixelFormat="فرمت پیکسل" +ColorSpace="فضای رنگی" ColorSpace.Default="پیش فرض" +ColorRange="محدوده رنگ" ColorRange.Default="پیش فرض" ColorRange.Partial="جزئی" ColorRange.Full="کامل" @@ -17,6 +19,8 @@ ChannelFormat.5_1ch="5.1ch" ChannelFormat.7_1ch="7.1ch" DeactivateWhenNotShowing="غیر فعال کردن زمانی که نمایش داده نشود" AutoStart="شروع خودکار در راه اندازی" +SwapFC-LFE="تعویض م ج و ج ف پ" +SwapFC-LFE.Tooltip="مبادله کانال مرکز جلو و کانال ج ف پ" VideoConnection="اتصال صوتی" AudioConnection="اتصال صوتی" diff --git a/plugins/decklink/data/locale/he-IL.ini b/plugins/decklink/data/locale/he-IL.ini index 1204764..72c3310 100644 --- a/plugins/decklink/data/locale/he-IL.ini +++ b/plugins/decklink/data/locale/he-IL.ini @@ -11,6 +11,15 @@ ColorRange.Partial="חלקי" ColorRange.Full="מלא" ChannelFormat="ערוץ" ChannelFormat.None="ללא" +ChannelFormat.2_0ch="2ch" +ChannelFormat.2_1ch="2.1ch" +ChannelFormat.4_0ch="4ch" +ChannelFormat.4_1ch="4.1ch" +ChannelFormat.5_1ch="5.1ch" +ChannelFormat.7_1ch="7.1ch" +DeactivateWhenNotShowing="השבת כאשר לא נראה" +AutoStart="הפעלה אוטומטית בפתיחה" +SwapFC-LFE="החלפת FC וLFE" VideoConnection="חיבור וידאו" AudioConnection="חיבור שמע" diff --git a/plugins/decklink/data/locale/kab-KAB.ini b/plugins/decklink/data/locale/kab-KAB.ini new file mode 100644 index 0000000..35cae93 --- /dev/null +++ b/plugins/decklink/data/locale/kab-KAB.ini @@ -0,0 +1,26 @@ +BlackmagicDevice="Ibenk Blackmagic" +Device="Ibenk" +Mode="Askar" +Buffering="Seqdec ajmaɛ di tkatut n weḥraz" +PixelFormat="Amasal n upiksel" +ColorSpace="Tallunt n yini" +ColorSpace.Default="Amezwar" +ColorRange="Tagrumma n yini" +ColorRange.Default="Amezwar" +ColorRange.Partial="Abruyan" +ColorRange.Full="Ummid" +ChannelFormat="Abadu" +ChannelFormat.None="Ulac" +ChannelFormat.2_0ch="2 n yibuda" +ChannelFormat.2_1ch="2.1 n yibuda" +ChannelFormat.4_0ch="4 n yibuda" +ChannelFormat.4_1ch="4.1 n yibuda" +ChannelFormat.5_1ch="5.1 n yibuda" +ChannelFormat.7_1ch="7.1 n yibuda" +DeactivateWhenNotShowing="Sens ma ur yettwabeqqeḍ ara" +AutoStart="Sekker s wudem awurman di tnekkra" +SwapFC-LFE="Semselsi gar FC akked LFE" +SwapFC-LFE.Tooltip="Semselsi gar ubadu alemmas n sdat akked ubadu LEF" +VideoConnection="Tuqqna n uvidyu" +AudioConnection="Tuqqna n umeslaw" + diff --git a/plugins/decklink/data/locale/ro-RO.ini b/plugins/decklink/data/locale/ro-RO.ini index ff6225f..75862e7 100644 --- a/plugins/decklink/data/locale/ro-RO.ini +++ b/plugins/decklink/data/locale/ro-RO.ini @@ -19,8 +19,8 @@ ChannelFormat.5_1ch="5.1ch" ChannelFormat.7_1ch="7.1ch" DeactivateWhenNotShowing="Dezactivează când nu se afișează" AutoStart="Pornire automată la lansare" -SwapFC-LFE="Schimbă FC și LFE" -SwapFC-LFE.Tooltip="Schimbă canalul din Front Center și canalul LFE" +SwapFC-LFE="Comută între FC și LFE" +SwapFC-LFE.Tooltip="Comută între canalul centru frontal (FC) și canalul cu efecte de frecvență joasă (LFE)" VideoConnection="Conexiune video" AudioConnection="Conexiune audio" diff --git a/plugins/decklink/data/locale/ru-RU.ini b/plugins/decklink/data/locale/ru-RU.ini index fccde7c..f9ab6b5 100644 --- a/plugins/decklink/data/locale/ru-RU.ini +++ b/plugins/decklink/data/locale/ru-RU.ini @@ -18,7 +18,7 @@ ChannelFormat.4_1ch="4.1-канальный" ChannelFormat.5_1ch="5.1-канальный" ChannelFormat.7_1ch="7.1-канальный" DeactivateWhenNotShowing="Выключать, когда не показывается" -AutoStart="Авто-старт при запуске" +AutoStart="Автозапуск при запуске" SwapFC-LFE="Обменять ПЦ и LFE" SwapFC-LFE.Tooltip="Обменять передний центральный канал и LFE канал" VideoConnection="Видео соединение" diff --git a/plugins/decklink/decklink-device-instance.cpp b/plugins/decklink/decklink-device-instance.cpp index f75cc72..4adc7e0 100644 --- a/plugins/decklink/decklink-device-instance.cpp +++ b/plugins/decklink/decklink-device-instance.cpp @@ -9,8 +9,14 @@ #include #include +#include #include +#include "OBSVideoFrame.h" + +#include +#include + static inline enum video_format ConvertPixelFormat(BMDPixelFormat format) { switch (format) { @@ -62,14 +68,23 @@ static inline audio_repack_mode_t ConvertRepackFormat(speaker_layout format, DeckLinkDeviceInstance::DeckLinkDeviceInstance(DecklinkBase *decklink_, DeckLinkDevice *device_) - : currentFrame(), currentPacket(), decklink(decklink_), device(device_) + : currentFrame(), + currentPacket(), + currentCaptions(), + decklink(decklink_), + device(device_) { currentPacket.samples_per_sec = 48000; currentPacket.speakers = SPEAKERS_STEREO; currentPacket.format = AUDIO_FORMAT_16BIT; } -DeckLinkDeviceInstance::~DeckLinkDeviceInstance() {} +DeckLinkDeviceInstance::~DeckLinkDeviceInstance() +{ + if (convertFrame) { + delete convertFrame; + } +} void DeckLinkDeviceInstance::HandleAudioPacket( IDeckLinkAudioInputPacket *audioPacket, const uint64_t timestamp) @@ -127,16 +142,47 @@ void DeckLinkDeviceInstance::HandleVideoFrame( if (videoFrame == nullptr) return; + IDeckLinkVideoFrameAncillaryPackets *packets; + + if (videoFrame->QueryInterface(IID_IDeckLinkVideoFrameAncillaryPackets, + (void **)&packets) == S_OK) { + IDeckLinkAncillaryPacketIterator *iterator; + packets->GetPacketIterator(&iterator); + + IDeckLinkAncillaryPacket *packet; + iterator->Next(&packet); + + if (packet) { + auto did = packet->GetDID(); + auto sdid = packet->GetSDID(); + + // Caption data + if (did == 0x61 && sdid == 0x01) { + this->HandleCaptionPacket(packet, timestamp); + } + + packet->Release(); + } + + iterator->Release(); + packets->Release(); + } + + IDeckLinkVideoConversion *frameConverter = + CreateVideoConversionInstance(); + + frameConverter->ConvertFrame(videoFrame, convertFrame); + void *bytes; - if (videoFrame->GetBytes(&bytes) != S_OK) { + if (convertFrame->GetBytes(&bytes) != S_OK) { LOG(LOG_WARNING, "Failed to get video frame data"); return; } currentFrame.data[0] = (uint8_t *)bytes; - currentFrame.linesize[0] = (uint32_t)videoFrame->GetRowBytes(); - currentFrame.width = (uint32_t)videoFrame->GetWidth(); - currentFrame.height = (uint32_t)videoFrame->GetHeight(); + currentFrame.linesize[0] = (uint32_t)convertFrame->GetRowBytes(); + currentFrame.width = (uint32_t)convertFrame->GetWidth(); + currentFrame.height = (uint32_t)convertFrame->GetHeight(); currentFrame.timestamp = timestamp; obs_source_output_video2( @@ -144,6 +190,97 @@ void DeckLinkDeviceInstance::HandleVideoFrame( ¤tFrame); } +void DeckLinkDeviceInstance::HandleCaptionPacket( + IDeckLinkAncillaryPacket *packet, const uint64_t timestamp) +{ + const void *data; + uint32_t size; + packet->GetBytes(bmdAncillaryPacketFormatUInt8, &data, &size); + + auto anc = (uint8_t *)data; + struct bitstream_reader reader; + bitstream_reader_init(&reader, anc, size); + + // header1 + bitstream_reader_r8(&reader); + // header2 + bitstream_reader_r8(&reader); + + // length + bitstream_reader_r8(&reader); + // frameRate + bitstream_reader_read_bits(&reader, 4); + //reserved + bitstream_reader_read_bits(&reader, 4); + + auto cdp_timecode_added = bitstream_reader_read_bits(&reader, 1); + // cdp_data_block_added + bitstream_reader_read_bits(&reader, 1); + // cdp_service_info_added + bitstream_reader_read_bits(&reader, 1); + // cdp_service_info_start + bitstream_reader_read_bits(&reader, 1); + // cdp_service_info_changed + bitstream_reader_read_bits(&reader, 1); + // cdp_service_info_end + bitstream_reader_read_bits(&reader, 1); + auto cdp_contains_captions = bitstream_reader_read_bits(&reader, 1); + //reserved + bitstream_reader_read_bits(&reader, 1); + + // cdp_counter + bitstream_reader_r8(&reader); + // cdp_counter2 + bitstream_reader_r8(&reader); + + if (cdp_timecode_added) { + // timecodeSectionID + bitstream_reader_r8(&reader); + //reserved + bitstream_reader_read_bits(&reader, 2); + bitstream_reader_read_bits(&reader, 2); + bitstream_reader_read_bits(&reader, 4); + // reserved + bitstream_reader_read_bits(&reader, 1); + bitstream_reader_read_bits(&reader, 3); + bitstream_reader_read_bits(&reader, 4); + bitstream_reader_read_bits(&reader, 1); + bitstream_reader_read_bits(&reader, 3); + bitstream_reader_read_bits(&reader, 4); + bitstream_reader_read_bits(&reader, 1); + bitstream_reader_read_bits(&reader, 1); + bitstream_reader_read_bits(&reader, 3); + bitstream_reader_read_bits(&reader, 4); + } + + if (cdp_contains_captions) { + // cdp_data_section + bitstream_reader_r8(&reader); + + //process_em_data_flag + bitstream_reader_read_bits(&reader, 1); + // process_cc_data_flag + bitstream_reader_read_bits(&reader, 1); + //additional_data_flag + bitstream_reader_read_bits(&reader, 1); + + auto cc_count = bitstream_reader_read_bits(&reader, 5); + + auto *outData = + (uint8_t *)bzalloc(sizeof(uint8_t) * cc_count * 3); + memcpy(outData, anc + reader.pos, cc_count * 3); + + currentCaptions.data = outData; + currentCaptions.timestamp = timestamp; + currentCaptions.packets = cc_count; + + obs_source_output_cea708( + static_cast(decklink)->GetSource(), + ¤tCaptions); + bfree(outData); + } +} + void DeckLinkDeviceInstance::FinalizeStream() { input->SetCallback(nullptr); @@ -189,6 +326,11 @@ void DeckLinkDeviceInstance::SetupVideoFormat(DeckLinkDeviceMode *mode_) currentFrame.color_range_min, currentFrame.color_range_max); + if (convertFrame) { + delete convertFrame; + } + convertFrame = new OBSVideoFrame(mode_->GetWidth(), mode_->GetHeight()); + #ifdef LOG_SETUP_VIDEO_FORMAT LOG(LOG_INFO, "Setup video format: %s, %s, %s", pixelFormat == bmdFormat8BitYUV ? "YUV" : "RGB", @@ -250,7 +392,7 @@ bool DeckLinkDeviceInstance::StartCapture(DeckLinkDeviceMode *mode_, bool isauto = mode_->GetName() == "Auto"; if (isauto) { displayMode = bmdModeNTSC; - pixelFormat = bmdFormat8BitYUV; + pixelFormat = bmdFormat10BitYUV; flags = bmdVideoInputEnableFormatDetection; } else { displayMode = mode_->GetDisplayMode(); @@ -487,13 +629,6 @@ HRESULT STDMETHODCALLTYPE DeckLinkDeviceInstance::VideoInputFormatChanged( BMDVideoInputFormatChangedEvents events, IDeckLinkDisplayMode *newMode, BMDDetectedVideoInputFormatFlags detectedSignalFlags) { - input->PauseStreams(); - - mode->SetMode(newMode); - - if (events & bmdVideoInputDisplayModeChanged) { - displayMode = mode->GetDisplayMode(); - } if (events & bmdVideoInputColorspaceChanged) { switch (detectedSignalFlags) { @@ -503,26 +638,31 @@ HRESULT STDMETHODCALLTYPE DeckLinkDeviceInstance::VideoInputFormatChanged( default: case bmdDetectedVideoInputYCbCr422: - pixelFormat = bmdFormat8BitYUV; + pixelFormat = bmdFormat10BitYUV; break; } } - const HRESULT videoResult = input->EnableVideoInput( - displayMode, pixelFormat, bmdVideoInputEnableFormatDetection); - if (videoResult != S_OK) { - LOG(LOG_ERROR, "Failed to enable video input"); - input->StopStreams(); - FinalizeStream(); + if (events & bmdVideoInputDisplayModeChanged) { + input->PauseStreams(); + mode->SetMode(newMode); + displayMode = mode->GetDisplayMode(); - return E_FAIL; + const HRESULT videoResult = input->EnableVideoInput( + displayMode, pixelFormat, + bmdVideoInputEnableFormatDetection); + if (videoResult != S_OK) { + LOG(LOG_ERROR, "Failed to enable video input"); + input->StopStreams(); + FinalizeStream(); + + return E_FAIL; + } + SetupVideoFormat(mode); + input->FlushStreams(); + input->StartStreams(); } - SetupVideoFormat(mode); - - input->FlushStreams(); - input->StartStreams(); - return S_OK; } diff --git a/plugins/decklink/decklink-device-instance.hpp b/plugins/decklink/decklink-device-instance.hpp index d2982bc..e6c3d69 100644 --- a/plugins/decklink/decklink-device-instance.hpp +++ b/plugins/decklink/decklink-device-instance.hpp @@ -6,6 +6,7 @@ #include #include "decklink-device.hpp" #include "../../libobs/media-io/video-scaler.h" +#include "OBSVideoFrame.h" class AudioRepacker; class DecklinkBase; @@ -14,6 +15,7 @@ class DeckLinkDeviceInstance : public IDeckLinkInputCallback { protected: struct obs_source_frame2 currentFrame; struct obs_source_audio currentPacket; + struct obs_source_cea_708 currentCaptions; DecklinkBase *decklink = nullptr; DeckLinkDevice *device = nullptr; DeckLinkDeviceMode *mode = nullptr; @@ -34,6 +36,7 @@ protected: speaker_layout channelFormat = SPEAKERS_STEREO; bool swap; + OBSVideoFrame *convertFrame = nullptr; IDeckLinkMutableVideoFrame *decklinkOutputFrame = nullptr; void FinalizeStream(); @@ -104,4 +107,6 @@ public: void DisplayVideoFrame(video_data *frame); void WriteAudio(audio_data *frames); + void HandleCaptionPacket(IDeckLinkAncillaryPacket *packet, + const uint64_t timestamp); }; diff --git a/plugins/decklink/decklink-device.cpp b/plugins/decklink/decklink-device.cpp index 2497735..2d6b489 100644 --- a/plugins/decklink/decklink-device.cpp +++ b/plugins/decklink/decklink-device.cpp @@ -30,10 +30,9 @@ ULONG DeckLinkDevice::Release() bool DeckLinkDevice::Init() { - ComPtr attributes; - const HRESULT result = device->QueryInterface(IID_IDeckLinkAttributes, - (void **)&attributes); - + ComPtr attributes; + const HRESULT result = device->QueryInterface( + IID_IDeckLinkProfileAttributes, (void **)&attributes); if (result == S_OK) { decklink_bool_t detectable = false; if (attributes->GetFlag(BMDDeckLinkSupportsInputFormatDetection, diff --git a/plugins/decklink/decklink-source.cpp b/plugins/decklink/decklink-source.cpp index 0b31623..1b31844 100644 --- a/plugins/decklink/decklink-source.cpp +++ b/plugins/decklink/decklink-source.cpp @@ -331,9 +331,9 @@ struct obs_source_info create_decklink_source_info() struct obs_source_info decklink_source_info = {}; decklink_source_info.id = "decklink-input"; decklink_source_info.type = OBS_SOURCE_TYPE_INPUT; - decklink_source_info.output_flags = OBS_SOURCE_ASYNC_VIDEO | - OBS_SOURCE_AUDIO | - OBS_SOURCE_DO_NOT_DUPLICATE; + decklink_source_info.output_flags = + OBS_SOURCE_ASYNC_VIDEO | OBS_SOURCE_AUDIO | + OBS_SOURCE_DO_NOT_DUPLICATE | OBS_SOURCE_CEA_708; decklink_source_info.create = decklink_create; decklink_source_info.destroy = decklink_destroy; decklink_source_info.get_defaults = decklink_get_defaults; diff --git a/plugins/decklink/linux/CMakeLists.txt b/plugins/decklink/linux/CMakeLists.txt index 5c11bf0..fdb96bf 100644 --- a/plugins/decklink/linux/CMakeLists.txt +++ b/plugins/decklink/linux/CMakeLists.txt @@ -5,6 +5,8 @@ if(DISABLE_DECKLINK) return() endif() +include_directories(${CMAKE_SOURCE_DIR}/deps/libcaption) + set(linux-decklink-sdk_HEADERS decklink-sdk/DeckLinkAPI.h decklink-sdk/DeckLinkAPIConfiguration.h @@ -34,6 +36,7 @@ set(linux-decklink_HEADERS ../audio-repack.h ../audio-repack.hpp ../util.hpp + ../OBSVideoFrame.h ) set(linux-decklink_SOURCES @@ -51,6 +54,7 @@ set(linux-decklink_SOURCES ../audio-repack.c platform.cpp ../util.cpp + ../OBSVideoFrame.cpp ) add_library(linux-decklink MODULE @@ -62,7 +66,7 @@ add_library(linux-decklink MODULE target_link_libraries(linux-decklink libobs - ) -set_target_properties(linux-decklink PROPERTIES FOLDER "plugins") + caption) +set_target_properties(linux-decklink PROPERTIES FOLDER "plugins/decklink") install_obs_plugin_with_data(linux-decklink ../data) diff --git a/plugins/decklink/linux/decklink-sdk/DeckLinkAPI.h b/plugins/decklink/linux/decklink-sdk/DeckLinkAPI.h index e113fc3..d9f532d 100644 --- a/plugins/decklink/linux/decklink-sdk/DeckLinkAPI.h +++ b/plugins/decklink/linux/decklink-sdk/DeckLinkAPI.h @@ -1,5 +1,5 @@ /* -LICENSE-START- -** Copyright (c) 2018 Blackmagic Design +** Copyright (c) 2020 Blackmagic Design ** ** Permission is hereby granted, free of charge, to any person or organization ** obtaining a copy of the software and accompanying documentation covered by @@ -7,14 +7,14 @@ ** execute, and transmit the Software, and to prepare derivative works of the ** Software, and to permit third-parties to whom the Software is furnished to ** do so, all subject to the following: -** +** ** The copyright notices in the Software and this entire statement, including ** the above license grant, this restriction and the following disclaimer, ** must be included in all copies of the Software, in whole or in part, and ** all derivative works of the Software, unless such copies or derivative ** works are solely in the form of machine-executable object code generated by ** a source language processor. -** +** ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT @@ -59,41 +59,45 @@ // Interface ID Declarations -BMD_CONST REFIID IID_IDeckLinkVideoOutputCallback = /* 20AA5225-1958-47CB-820B-80A8D521A6EE */ {0x20,0xAA,0x52,0x25,0x19,0x58,0x47,0xCB,0x82,0x0B,0x80,0xA8,0xD5,0x21,0xA6,0xEE}; -BMD_CONST REFIID IID_IDeckLinkInputCallback = /* DD04E5EC-7415-42AB-AE4A-E80C4DFC044A */ {0xDD,0x04,0xE5,0xEC,0x74,0x15,0x42,0xAB,0xAE,0x4A,0xE8,0x0C,0x4D,0xFC,0x04,0x4A}; -BMD_CONST REFIID IID_IDeckLinkEncoderInputCallback = /* ACF13E61-F4A0-4974-A6A7-59AFF6268B31 */ {0xAC,0xF1,0x3E,0x61,0xF4,0xA0,0x49,0x74,0xA6,0xA7,0x59,0xAF,0xF6,0x26,0x8B,0x31}; -BMD_CONST REFIID IID_IDeckLinkMemoryAllocator = /* B36EB6E7-9D29-4AA8-92EF-843B87A289E8 */ {0xB3,0x6E,0xB6,0xE7,0x9D,0x29,0x4A,0xA8,0x92,0xEF,0x84,0x3B,0x87,0xA2,0x89,0xE8}; -BMD_CONST REFIID IID_IDeckLinkAudioOutputCallback = /* 403C681B-7F46-4A12-B993-2BB127084EE6 */ {0x40,0x3C,0x68,0x1B,0x7F,0x46,0x4A,0x12,0xB9,0x93,0x2B,0xB1,0x27,0x08,0x4E,0xE6}; -BMD_CONST REFIID IID_IDeckLinkIterator = /* 50FB36CD-3063-4B73-BDBB-958087F2D8BA */ {0x50,0xFB,0x36,0xCD,0x30,0x63,0x4B,0x73,0xBD,0xBB,0x95,0x80,0x87,0xF2,0xD8,0xBA}; -BMD_CONST REFIID IID_IDeckLinkAPIInformation = /* 7BEA3C68-730D-4322-AF34-8A7152B532A4 */ {0x7B,0xEA,0x3C,0x68,0x73,0x0D,0x43,0x22,0xAF,0x34,0x8A,0x71,0x52,0xB5,0x32,0xA4}; -BMD_CONST REFIID IID_IDeckLinkOutput = /* CC5C8A6E-3F2F-4B3A-87EA-FD78AF300564 */ {0xCC,0x5C,0x8A,0x6E,0x3F,0x2F,0x4B,0x3A,0x87,0xEA,0xFD,0x78,0xAF,0x30,0x05,0x64}; -BMD_CONST REFIID IID_IDeckLinkInput = /* AF22762B-DFAC-4846-AA79-FA8883560995 */ {0xAF,0x22,0x76,0x2B,0xDF,0xAC,0x48,0x46,0xAA,0x79,0xFA,0x88,0x83,0x56,0x09,0x95}; -BMD_CONST REFIID IID_IDeckLinkHDMIInputEDID = /* ABBBACBC-45BC-4665-9D92-ACE6E5A97902 */ {0xAB,0xBB,0xAC,0xBC,0x45,0xBC,0x46,0x65,0x9D,0x92,0xAC,0xE6,0xE5,0xA9,0x79,0x02}; -BMD_CONST REFIID IID_IDeckLinkEncoderInput = /* 270587DA-6B7D-42E7-A1F0-6D853F581185 */ {0x27,0x05,0x87,0xDA,0x6B,0x7D,0x42,0xE7,0xA1,0xF0,0x6D,0x85,0x3F,0x58,0x11,0x85}; -BMD_CONST REFIID IID_IDeckLinkVideoFrame = /* 3F716FE0-F023-4111-BE5D-EF4414C05B17 */ {0x3F,0x71,0x6F,0xE0,0xF0,0x23,0x41,0x11,0xBE,0x5D,0xEF,0x44,0x14,0xC0,0x5B,0x17}; -BMD_CONST REFIID IID_IDeckLinkMutableVideoFrame = /* 69E2639F-40DA-4E19-B6F2-20ACE815C390 */ {0x69,0xE2,0x63,0x9F,0x40,0xDA,0x4E,0x19,0xB6,0xF2,0x20,0xAC,0xE8,0x15,0xC3,0x90}; -BMD_CONST REFIID IID_IDeckLinkVideoFrame3DExtensions = /* DA0F7E4A-EDC7-48A8-9CDD-2DB51C729CD7 */ {0xDA,0x0F,0x7E,0x4A,0xED,0xC7,0x48,0xA8,0x9C,0xDD,0x2D,0xB5,0x1C,0x72,0x9C,0xD7}; -BMD_CONST REFIID IID_IDeckLinkVideoFrameMetadataExtensions = /* D5973DC9-6432-46D0-8F0B-2496F8A1238F */ {0xD5,0x97,0x3D,0xC9,0x64,0x32,0x46,0xD0,0x8F,0x0B,0x24,0x96,0xF8,0xA1,0x23,0x8F}; -BMD_CONST REFIID IID_IDeckLinkVideoInputFrame = /* 05CFE374-537C-4094-9A57-680525118F44 */ {0x05,0xCF,0xE3,0x74,0x53,0x7C,0x40,0x94,0x9A,0x57,0x68,0x05,0x25,0x11,0x8F,0x44}; -BMD_CONST REFIID IID_IDeckLinkAncillaryPacket = /* CC5BBF7E-029C-4D3B-9158-6000EF5E3670 */ {0xCC,0x5B,0xBF,0x7E,0x02,0x9C,0x4D,0x3B,0x91,0x58,0x60,0x00,0xEF,0x5E,0x36,0x70}; -BMD_CONST REFIID IID_IDeckLinkAncillaryPacketIterator = /* 3FC8994B-88FB-4C17-968F-9AAB69D964A7 */ {0x3F,0xC8,0x99,0x4B,0x88,0xFB,0x4C,0x17,0x96,0x8F,0x9A,0xAB,0x69,0xD9,0x64,0xA7}; -BMD_CONST REFIID IID_IDeckLinkVideoFrameAncillaryPackets = /* 6C186C0F-459E-41D8-AEE2-4812D81AEE68 */ {0x6C,0x18,0x6C,0x0F,0x45,0x9E,0x41,0xD8,0xAE,0xE2,0x48,0x12,0xD8,0x1A,0xEE,0x68}; -BMD_CONST REFIID IID_IDeckLinkVideoFrameAncillary = /* 732E723C-D1A4-4E29-9E8E-4A88797A0004 */ {0x73,0x2E,0x72,0x3C,0xD1,0xA4,0x4E,0x29,0x9E,0x8E,0x4A,0x88,0x79,0x7A,0x00,0x04}; -BMD_CONST REFIID IID_IDeckLinkEncoderPacket = /* B693F36C-316E-4AF1-B6C2-F389A4BCA620 */ {0xB6,0x93,0xF3,0x6C,0x31,0x6E,0x4A,0xF1,0xB6,0xC2,0xF3,0x89,0xA4,0xBC,0xA6,0x20}; -BMD_CONST REFIID IID_IDeckLinkEncoderVideoPacket = /* 4E7FD944-E8C7-4EAC-B8C0-7B77F80F5AE0 */ {0x4E,0x7F,0xD9,0x44,0xE8,0xC7,0x4E,0xAC,0xB8,0xC0,0x7B,0x77,0xF8,0x0F,0x5A,0xE0}; -BMD_CONST REFIID IID_IDeckLinkEncoderAudioPacket = /* 49E8EDC8-693B-4E14-8EF6-12C658F5A07A */ {0x49,0xE8,0xED,0xC8,0x69,0x3B,0x4E,0x14,0x8E,0xF6,0x12,0xC6,0x58,0xF5,0xA0,0x7A}; -BMD_CONST REFIID IID_IDeckLinkH265NALPacket = /* 639C8E0B-68D5-4BDE-A6D4-95F3AEAFF2E7 */ {0x63,0x9C,0x8E,0x0B,0x68,0xD5,0x4B,0xDE,0xA6,0xD4,0x95,0xF3,0xAE,0xAF,0xF2,0xE7}; -BMD_CONST REFIID IID_IDeckLinkAudioInputPacket = /* E43D5870-2894-11DE-8C30-0800200C9A66 */ {0xE4,0x3D,0x58,0x70,0x28,0x94,0x11,0xDE,0x8C,0x30,0x08,0x00,0x20,0x0C,0x9A,0x66}; -BMD_CONST REFIID IID_IDeckLinkScreenPreviewCallback = /* B1D3F49A-85FE-4C5D-95C8-0B5D5DCCD438 */ {0xB1,0xD3,0xF4,0x9A,0x85,0xFE,0x4C,0x5D,0x95,0xC8,0x0B,0x5D,0x5D,0xCC,0xD4,0x38}; -BMD_CONST REFIID IID_IDeckLinkGLScreenPreviewHelper = /* 504E2209-CAC7-4C1A-9FB4-C5BB6274D22F */ {0x50,0x4E,0x22,0x09,0xCA,0xC7,0x4C,0x1A,0x9F,0xB4,0xC5,0xBB,0x62,0x74,0xD2,0x2F}; -BMD_CONST REFIID IID_IDeckLinkNotificationCallback = /* B002A1EC-070D-4288-8289-BD5D36E5FF0D */ {0xB0,0x02,0xA1,0xEC,0x07,0x0D,0x42,0x88,0x82,0x89,0xBD,0x5D,0x36,0xE5,0xFF,0x0D}; -BMD_CONST REFIID IID_IDeckLinkNotification = /* 0A1FB207-E215-441B-9B19-6FA1575946C5 */ {0x0A,0x1F,0xB2,0x07,0xE2,0x15,0x44,0x1B,0x9B,0x19,0x6F,0xA1,0x57,0x59,0x46,0xC5}; -BMD_CONST REFIID IID_IDeckLinkAttributes = /* ABC11843-D966-44CB-96E2-A1CB5D3135C4 */ {0xAB,0xC1,0x18,0x43,0xD9,0x66,0x44,0xCB,0x96,0xE2,0xA1,0xCB,0x5D,0x31,0x35,0xC4}; -BMD_CONST REFIID IID_IDeckLinkStatus = /* 5F558200-4028-49BC-BEAC-DB3FA4A96E46 */ {0x5F,0x55,0x82,0x00,0x40,0x28,0x49,0xBC,0xBE,0xAC,0xDB,0x3F,0xA4,0xA9,0x6E,0x46}; -BMD_CONST REFIID IID_IDeckLinkKeyer = /* 89AFCAF5-65F8-421E-98F7-96FE5F5BFBA3 */ {0x89,0xAF,0xCA,0xF5,0x65,0xF8,0x42,0x1E,0x98,0xF7,0x96,0xFE,0x5F,0x5B,0xFB,0xA3}; -BMD_CONST REFIID IID_IDeckLinkVideoConversion = /* 3BBCB8A2-DA2C-42D9-B5D8-88083644E99A */ {0x3B,0xBC,0xB8,0xA2,0xDA,0x2C,0x42,0xD9,0xB5,0xD8,0x88,0x08,0x36,0x44,0xE9,0x9A}; -BMD_CONST REFIID IID_IDeckLinkDeviceNotificationCallback = /* 4997053B-0ADF-4CC8-AC70-7A50C4BE728F */ {0x49,0x97,0x05,0x3B,0x0A,0xDF,0x4C,0xC8,0xAC,0x70,0x7A,0x50,0xC4,0xBE,0x72,0x8F}; -BMD_CONST REFIID IID_IDeckLinkDiscovery = /* CDBF631C-BC76-45FA-B44D-C55059BC6101 */ {0xCD,0xBF,0x63,0x1C,0xBC,0x76,0x45,0xFA,0xB4,0x4D,0xC5,0x50,0x59,0xBC,0x61,0x01}; +BMD_CONST REFIID IID_IDeckLinkVideoOutputCallback = /* 20AA5225-1958-47CB-820B-80A8D521A6EE */ { 0x20,0xAA,0x52,0x25,0x19,0x58,0x47,0xCB,0x82,0x0B,0x80,0xA8,0xD5,0x21,0xA6,0xEE }; +BMD_CONST REFIID IID_IDeckLinkInputCallback = /* C6FCE4C9-C4E4-4047-82FB-5D238232A902 */ { 0xC6,0xFC,0xE4,0xC9,0xC4,0xE4,0x40,0x47,0x82,0xFB,0x5D,0x23,0x82,0x32,0xA9,0x02 }; +BMD_CONST REFIID IID_IDeckLinkEncoderInputCallback = /* ACF13E61-F4A0-4974-A6A7-59AFF6268B31 */ { 0xAC,0xF1,0x3E,0x61,0xF4,0xA0,0x49,0x74,0xA6,0xA7,0x59,0xAF,0xF6,0x26,0x8B,0x31 }; +BMD_CONST REFIID IID_IDeckLinkMemoryAllocator = /* B36EB6E7-9D29-4AA8-92EF-843B87A289E8 */ { 0xB3,0x6E,0xB6,0xE7,0x9D,0x29,0x4A,0xA8,0x92,0xEF,0x84,0x3B,0x87,0xA2,0x89,0xE8 }; +BMD_CONST REFIID IID_IDeckLinkAudioOutputCallback = /* 403C681B-7F46-4A12-B993-2BB127084EE6 */ { 0x40,0x3C,0x68,0x1B,0x7F,0x46,0x4A,0x12,0xB9,0x93,0x2B,0xB1,0x27,0x08,0x4E,0xE6 }; +BMD_CONST REFIID IID_IDeckLinkIterator = /* 50FB36CD-3063-4B73-BDBB-958087F2D8BA */ { 0x50,0xFB,0x36,0xCD,0x30,0x63,0x4B,0x73,0xBD,0xBB,0x95,0x80,0x87,0xF2,0xD8,0xBA }; +BMD_CONST REFIID IID_IDeckLinkAPIInformation = /* 7BEA3C68-730D-4322-AF34-8A7152B532A4 */ { 0x7B,0xEA,0x3C,0x68,0x73,0x0D,0x43,0x22,0xAF,0x34,0x8A,0x71,0x52,0xB5,0x32,0xA4 }; +BMD_CONST REFIID IID_IDeckLinkOutput = /* BE2D9020-461E-442F-84B7-E949CB953B9D */ { 0xBE,0x2D,0x90,0x20,0x46,0x1E,0x44,0x2F,0x84,0xB7,0xE9,0x49,0xCB,0x95,0x3B,0x9D }; +BMD_CONST REFIID IID_IDeckLinkInput = /* C21CDB6E-F414-46E4-A636-80A566E0ED37 */ { 0xC2,0x1C,0xDB,0x6E,0xF4,0x14,0x46,0xE4,0xA6,0x36,0x80,0xA5,0x66,0xE0,0xED,0x37 }; +BMD_CONST REFIID IID_IDeckLinkHDMIInputEDID = /* ABBBACBC-45BC-4665-9D92-ACE6E5A97902 */ { 0xAB,0xBB,0xAC,0xBC,0x45,0xBC,0x46,0x65,0x9D,0x92,0xAC,0xE6,0xE5,0xA9,0x79,0x02 }; +BMD_CONST REFIID IID_IDeckLinkEncoderInput = /* F222551D-13DF-4FD8-B587-9D4F19EC12C9 */ { 0xF2,0x22,0x55,0x1D,0x13,0xDF,0x4F,0xD8,0xB5,0x87,0x9D,0x4F,0x19,0xEC,0x12,0xC9 }; +BMD_CONST REFIID IID_IDeckLinkVideoFrame = /* 3F716FE0-F023-4111-BE5D-EF4414C05B17 */ { 0x3F,0x71,0x6F,0xE0,0xF0,0x23,0x41,0x11,0xBE,0x5D,0xEF,0x44,0x14,0xC0,0x5B,0x17 }; +BMD_CONST REFIID IID_IDeckLinkMutableVideoFrame = /* 69E2639F-40DA-4E19-B6F2-20ACE815C390 */ { 0x69,0xE2,0x63,0x9F,0x40,0xDA,0x4E,0x19,0xB6,0xF2,0x20,0xAC,0xE8,0x15,0xC3,0x90 }; +BMD_CONST REFIID IID_IDeckLinkVideoFrame3DExtensions = /* DA0F7E4A-EDC7-48A8-9CDD-2DB51C729CD7 */ { 0xDA,0x0F,0x7E,0x4A,0xED,0xC7,0x48,0xA8,0x9C,0xDD,0x2D,0xB5,0x1C,0x72,0x9C,0xD7 }; +BMD_CONST REFIID IID_IDeckLinkVideoFrameMetadataExtensions = /* E232A5B7-4DB4-44C9-9152-F47C12E5F051 */ { 0xE2,0x32,0xA5,0xB7,0x4D,0xB4,0x44,0xC9,0x91,0x52,0xF4,0x7C,0x12,0xE5,0xF0,0x51 }; +BMD_CONST REFIID IID_IDeckLinkVideoInputFrame = /* 05CFE374-537C-4094-9A57-680525118F44 */ { 0x05,0xCF,0xE3,0x74,0x53,0x7C,0x40,0x94,0x9A,0x57,0x68,0x05,0x25,0x11,0x8F,0x44 }; +BMD_CONST REFIID IID_IDeckLinkAncillaryPacket = /* CC5BBF7E-029C-4D3B-9158-6000EF5E3670 */ { 0xCC,0x5B,0xBF,0x7E,0x02,0x9C,0x4D,0x3B,0x91,0x58,0x60,0x00,0xEF,0x5E,0x36,0x70 }; +BMD_CONST REFIID IID_IDeckLinkAncillaryPacketIterator = /* 3FC8994B-88FB-4C17-968F-9AAB69D964A7 */ { 0x3F,0xC8,0x99,0x4B,0x88,0xFB,0x4C,0x17,0x96,0x8F,0x9A,0xAB,0x69,0xD9,0x64,0xA7 }; +BMD_CONST REFIID IID_IDeckLinkVideoFrameAncillaryPackets = /* 6C186C0F-459E-41D8-AEE2-4812D81AEE68 */ { 0x6C,0x18,0x6C,0x0F,0x45,0x9E,0x41,0xD8,0xAE,0xE2,0x48,0x12,0xD8,0x1A,0xEE,0x68 }; +BMD_CONST REFIID IID_IDeckLinkVideoFrameAncillary = /* 732E723C-D1A4-4E29-9E8E-4A88797A0004 */ { 0x73,0x2E,0x72,0x3C,0xD1,0xA4,0x4E,0x29,0x9E,0x8E,0x4A,0x88,0x79,0x7A,0x00,0x04 }; +BMD_CONST REFIID IID_IDeckLinkEncoderPacket = /* B693F36C-316E-4AF1-B6C2-F389A4BCA620 */ { 0xB6,0x93,0xF3,0x6C,0x31,0x6E,0x4A,0xF1,0xB6,0xC2,0xF3,0x89,0xA4,0xBC,0xA6,0x20 }; +BMD_CONST REFIID IID_IDeckLinkEncoderVideoPacket = /* 4E7FD944-E8C7-4EAC-B8C0-7B77F80F5AE0 */ { 0x4E,0x7F,0xD9,0x44,0xE8,0xC7,0x4E,0xAC,0xB8,0xC0,0x7B,0x77,0xF8,0x0F,0x5A,0xE0 }; +BMD_CONST REFIID IID_IDeckLinkEncoderAudioPacket = /* 49E8EDC8-693B-4E14-8EF6-12C658F5A07A */ { 0x49,0xE8,0xED,0xC8,0x69,0x3B,0x4E,0x14,0x8E,0xF6,0x12,0xC6,0x58,0xF5,0xA0,0x7A }; +BMD_CONST REFIID IID_IDeckLinkH265NALPacket = /* 639C8E0B-68D5-4BDE-A6D4-95F3AEAFF2E7 */ { 0x63,0x9C,0x8E,0x0B,0x68,0xD5,0x4B,0xDE,0xA6,0xD4,0x95,0xF3,0xAE,0xAF,0xF2,0xE7 }; +BMD_CONST REFIID IID_IDeckLinkAudioInputPacket = /* E43D5870-2894-11DE-8C30-0800200C9A66 */ { 0xE4,0x3D,0x58,0x70,0x28,0x94,0x11,0xDE,0x8C,0x30,0x08,0x00,0x20,0x0C,0x9A,0x66 }; +BMD_CONST REFIID IID_IDeckLinkScreenPreviewCallback = /* B1D3F49A-85FE-4C5D-95C8-0B5D5DCCD438 */ { 0xB1,0xD3,0xF4,0x9A,0x85,0xFE,0x4C,0x5D,0x95,0xC8,0x0B,0x5D,0x5D,0xCC,0xD4,0x38 }; +BMD_CONST REFIID IID_IDeckLinkGLScreenPreviewHelper = /* 504E2209-CAC7-4C1A-9FB4-C5BB6274D22F */ { 0x50,0x4E,0x22,0x09,0xCA,0xC7,0x4C,0x1A,0x9F,0xB4,0xC5,0xBB,0x62,0x74,0xD2,0x2F }; +BMD_CONST REFIID IID_IDeckLinkNotificationCallback = /* B002A1EC-070D-4288-8289-BD5D36E5FF0D */ { 0xB0,0x02,0xA1,0xEC,0x07,0x0D,0x42,0x88,0x82,0x89,0xBD,0x5D,0x36,0xE5,0xFF,0x0D }; +BMD_CONST REFIID IID_IDeckLinkNotification = /* B85DF4C8-BDF5-47C1-8064-28162EBDD4EB */ { 0xB8,0x5D,0xF4,0xC8,0xBD,0xF5,0x47,0xC1,0x80,0x64,0x28,0x16,0x2E,0xBD,0xD4,0xEB }; +BMD_CONST REFIID IID_IDeckLinkProfileAttributes = /* 17D4BF8E-4911-473A-80A0-731CF6FF345B */ { 0x17,0xD4,0xBF,0x8E,0x49,0x11,0x47,0x3A,0x80,0xA0,0x73,0x1C,0xF6,0xFF,0x34,0x5B }; +BMD_CONST REFIID IID_IDeckLinkProfileIterator = /* 29E5A8C0-8BE4-46EB-93AC-31DAAB5B7BF2 */ { 0x29,0xE5,0xA8,0xC0,0x8B,0xE4,0x46,0xEB,0x93,0xAC,0x31,0xDA,0xAB,0x5B,0x7B,0xF2 }; +BMD_CONST REFIID IID_IDeckLinkProfile = /* 16093466-674A-432B-9DA0-1AC2C5A8241C */ { 0x16,0x09,0x34,0x66,0x67,0x4A,0x43,0x2B,0x9D,0xA0,0x1A,0xC2,0xC5,0xA8,0x24,0x1C }; +BMD_CONST REFIID IID_IDeckLinkProfileCallback = /* A4F9341E-97AA-4E04-8935-15F809898CEA */ { 0xA4,0xF9,0x34,0x1E,0x97,0xAA,0x4E,0x04,0x89,0x35,0x15,0xF8,0x09,0x89,0x8C,0xEA }; +BMD_CONST REFIID IID_IDeckLinkProfileManager = /* 30D41429-3998-4B6D-84F8-78C94A797C6E */ { 0x30,0xD4,0x14,0x29,0x39,0x98,0x4B,0x6D,0x84,0xF8,0x78,0xC9,0x4A,0x79,0x7C,0x6E }; +BMD_CONST REFIID IID_IDeckLinkStatus = /* 5F558200-4028-49BC-BEAC-DB3FA4A96E46 */ { 0x5F,0x55,0x82,0x00,0x40,0x28,0x49,0xBC,0xBE,0xAC,0xDB,0x3F,0xA4,0xA9,0x6E,0x46 }; +BMD_CONST REFIID IID_IDeckLinkKeyer = /* 89AFCAF5-65F8-421E-98F7-96FE5F5BFBA3 */ { 0x89,0xAF,0xCA,0xF5,0x65,0xF8,0x42,0x1E,0x98,0xF7,0x96,0xFE,0x5F,0x5B,0xFB,0xA3 }; +BMD_CONST REFIID IID_IDeckLinkVideoConversion = /* 3BBCB8A2-DA2C-42D9-B5D8-88083644E99A */ { 0x3B,0xBC,0xB8,0xA2,0xDA,0x2C,0x42,0xD9,0xB5,0xD8,0x88,0x08,0x36,0x44,0xE9,0x9A }; +BMD_CONST REFIID IID_IDeckLinkDeviceNotificationCallback = /* 4997053B-0ADF-4CC8-AC70-7A50C4BE728F */ { 0x49,0x97,0x05,0x3B,0x0A,0xDF,0x4C,0xC8,0xAC,0x70,0x7A,0x50,0xC4,0xBE,0x72,0x8F }; +BMD_CONST REFIID IID_IDeckLinkDiscovery = /* CDBF631C-BC76-45FA-B44D-C55059BC6101 */ { 0xCD,0xBF,0x63,0x1C,0xBC,0x76,0x45,0xFA,0xB4,0x4D,0xC5,0x50,0x59,0xBC,0x61,0x01 }; /* Enum BMDVideoOutputFlags - Flags to control the output of ancillary data along with video. */ @@ -103,7 +107,21 @@ enum _BMDVideoOutputFlags { bmdVideoOutputVANC = 1 << 0, bmdVideoOutputVITC = 1 << 1, bmdVideoOutputRP188 = 1 << 2, - bmdVideoOutputDualStream3D = 1 << 4 + bmdVideoOutputDualStream3D = 1 << 4, + bmdVideoOutputSynchronizeToPlaybackGroup = 1 << 6 +}; + +/* Enum BMDSupportedVideoModeFlags - Flags to describe supported video modes */ + +typedef uint32_t BMDSupportedVideoModeFlags; +enum _BMDSupportedVideoModeFlags { + bmdSupportedVideoModeDefault = 0, + bmdSupportedVideoModeKeying = 1 << 0, + bmdSupportedVideoModeDualStream3D = 1 << 1, + bmdSupportedVideoModeSDISingleLink = 1 << 2, + bmdSupportedVideoModeSDIDualLink = 1 << 3, + bmdSupportedVideoModeSDIQuadLink = 1 << 4, + bmdSupportedVideoModeInAnyProfile = 1 << 5 }; /* Enum BMDPacketType - Type of packet */ @@ -121,7 +139,6 @@ enum _BMDFrameFlags { bmdFrameFlagDefault = 0, bmdFrameFlagFlipVertical = 1 << 0, bmdFrameContainsHDRMetadata = 1 << 1, - bmdFrameContainsCintelMetadata = 1 << 2, /* Flags that are applicable only to instances of IDeckLinkVideoInputFrame */ @@ -135,7 +152,8 @@ typedef uint32_t BMDVideoInputFlags; enum _BMDVideoInputFlags { bmdVideoInputFlagDefault = 0, bmdVideoInputEnableFormatDetection = 1 << 0, - bmdVideoInputDualStream3D = 1 << 1 + bmdVideoInputDualStream3D = 1 << 1, + bmdVideoInputSynchronizeToCaptureGroup = 1 << 2 }; /* Enum BMDVideoInputFormatChangedEvents - Bitmask passed to the VideoInputFormatChanged notification to identify the properties of the input signal that have changed */ @@ -153,7 +171,10 @@ typedef uint32_t BMDDetectedVideoInputFormatFlags; enum _BMDDetectedVideoInputFormatFlags { bmdDetectedVideoInputYCbCr422 = 1 << 0, bmdDetectedVideoInputRGB444 = 1 << 1, - bmdDetectedVideoInputDualStream3D = 1 << 2 + bmdDetectedVideoInputDualStream3D = 1 << 2, + bmdDetectedVideoInput12BitDepth = 1 << 3, + bmdDetectedVideoInput10BitDepth = 1 << 4, + bmdDetectedVideoInput8BitDepth = 1 << 5 }; /* Enum BMDDeckLinkCapturePassthroughMode - Enumerates whether the video output is electrically connected to the video input or if the clean switching mode is enabled */ @@ -169,10 +190,10 @@ enum _BMDDeckLinkCapturePassthroughMode { typedef uint32_t BMDOutputFrameCompletionResult; enum _BMDOutputFrameCompletionResult { - bmdOutputFrameCompleted, - bmdOutputFrameDisplayedLate, - bmdOutputFrameDropped, - bmdOutputFrameFlushed + bmdOutputFrameCompleted, + bmdOutputFrameDisplayedLate, + bmdOutputFrameDropped, + bmdOutputFrameFlushed }; /* Enum BMDReferenceStatus - GenLock input status */ @@ -209,18 +230,9 @@ enum _BMDAudioSampleType { typedef uint32_t BMDAudioOutputStreamType; enum _BMDAudioOutputStreamType { - bmdAudioOutputStreamContinuous, - bmdAudioOutputStreamContinuousDontResample, - bmdAudioOutputStreamTimestamped -}; - -/* Enum BMDDisplayModeSupport - Output mode supported flags */ - -typedef uint32_t BMDDisplayModeSupport; -enum _BMDDisplayModeSupport { - bmdDisplayModeNotSupported = 0, - bmdDisplayModeSupported, - bmdDisplayModeSupportedWithConversion + bmdAudioOutputStreamContinuous, + bmdAudioOutputStreamContinuousDontResample, + bmdAudioOutputStreamTimestamped }; /* Enum BMDAncillaryPacketFormat - Ancillary packet format */ @@ -239,7 +251,8 @@ enum _BMDTimecodeFormat { bmdTimecodeRP188VITC1 = /* 'rpv1' */ 0x72707631, // RP188 timecode where DBB1 equals VITC1 (line 9) bmdTimecodeRP188VITC2 = /* 'rp12' */ 0x72703132, // RP188 timecode where DBB1 equals VITC2 (line 9 for progressive or line 571 for interlaced/PsF) bmdTimecodeRP188LTC = /* 'rplt' */ 0x72706C74, // RP188 timecode where DBB1 equals LTC (line 10) - bmdTimecodeRP188Any = /* 'rp18' */ 0x72703138, // For capture: return the first valid timecode in {VITC1, LTC ,VITC2} - For playback: set the timecode as VITC1 + bmdTimecodeRP188HighFrameRate = /* 'rphr' */ 0x72706872, // RP188 timecode where DBB1 is an HFRTC (SMPTE ST 12-3), the only timecode allowing the frame value to go above 30 + bmdTimecodeRP188Any = /* 'rp18' */ 0x72703138, // Convenience for capture, returning the first valid timecode in {HFRTC (if supported), VITC1, LTC, VITC2} bmdTimecodeVITC = /* 'vitc' */ 0x76697463, bmdTimecodeVITCField2 = /* 'vit2' */ 0x76697432, bmdTimecodeSerial = /* 'seri' */ 0x73657269 @@ -364,15 +377,18 @@ enum _BMDColorspace { typedef uint32_t BMDDynamicRange; enum _BMDDynamicRange { - bmdDynamicRangeSDR = 0, - bmdDynamicRangeHDRStaticPQ = 1 << 29, // SMPTE ST 2084 - bmdDynamicRangeHDRStaticHLG = 1 << 30 // ITU-R BT.2100-0 + bmdDynamicRangeSDR = 0, // Standard Dynamic Range in accordance with SMPTE ST 2036-1 + bmdDynamicRangeHDRStaticPQ = 1 << 29, // High Dynamic Range PQ in accordance with SMPTE ST 2084 + bmdDynamicRangeHDRStaticHLG = 1 << 30 // High Dynamic Range HLG in accordance with ITU-R BT.2100-0 }; /* Enum BMDDeckLinkHDMIInputEDIDID - DeckLink HDMI Input EDID ID */ typedef uint32_t BMDDeckLinkHDMIInputEDIDID; enum _BMDDeckLinkHDMIInputEDIDID { + + /* Integers */ + bmdDeckLinkHDMIInputEDIDDynamicRange = /* 'HIDy' */ 0x48494479 // Parameter is of type BMDDynamicRange. Default is (bmdDynamicRangeSDR|bmdDynamicRangeHDRStaticPQ) }; @@ -380,39 +396,17 @@ enum _BMDDeckLinkHDMIInputEDIDID { typedef uint32_t BMDDeckLinkFrameMetadataID; enum _BMDDeckLinkFrameMetadataID { + + /* Colorspace Metadata - Integers */ + bmdDeckLinkFrameMetadataColorspace = /* 'cspc' */ 0x63737063, // Colorspace of video frame (see BMDColorspace) + + /* HDR Metadata - Integers */ + bmdDeckLinkFrameMetadataHDRElectroOpticalTransferFunc = /* 'eotf' */ 0x656F7466, // EOTF in range 0-7 as per CEA 861.3 - bmdDeckLinkFrameMetadataCintelFilmType = /* 'cfty' */ 0x63667479, // Current film type - bmdDeckLinkFrameMetadataCintelFilmGauge = /* 'cfga' */ 0x63666761, // Current film gauge - bmdDeckLinkFrameMetadataCintelOffsetDetectedHorizontal = /* 'odfh' */ 0x6F646668, // Horizontal offset (pixels) detected in image - bmdDeckLinkFrameMetadataCintelOffsetDetectedVertical = /* 'odfv' */ 0x6F646676, // Vertical offset (pixels) detected in image - bmdDeckLinkFrameMetadataCintelKeykodeLow = /* 'ckkl' */ 0x636B6B6C, // Raw keykode value - low 64 bits - bmdDeckLinkFrameMetadataCintelKeykodeHigh = /* 'ckkh' */ 0x636B6B68, // Raw keykode value - high 64 bits - bmdDeckLinkFrameMetadataCintelTile1Size = /* 'ct1s' */ 0x63743173, // Size in bytes of compressed raw tile 1 - bmdDeckLinkFrameMetadataCintelTile2Size = /* 'ct2s' */ 0x63743273, // Size in bytes of compressed raw tile 2 - bmdDeckLinkFrameMetadataCintelTile3Size = /* 'ct3s' */ 0x63743373, // Size in bytes of compressed raw tile 3 - bmdDeckLinkFrameMetadataCintelTile4Size = /* 'ct4s' */ 0x63743473, // Size in bytes of compressed raw tile 4 - bmdDeckLinkFrameMetadataCintelImageWidth = /* 'IWPx' */ 0x49575078, // Width in pixels of image - bmdDeckLinkFrameMetadataCintelImageHeight = /* 'IHPx' */ 0x49485078, // Height in pixels of image - bmdDeckLinkFrameMetadataCintelLinearMaskingRedInRed = /* 'mrir' */ 0x6D726972, // Red in red linear masking parameter - bmdDeckLinkFrameMetadataCintelLinearMaskingGreenInRed = /* 'mgir' */ 0x6D676972, // Green in red linear masking parameter - bmdDeckLinkFrameMetadataCintelLinearMaskingBlueInRed = /* 'mbir' */ 0x6D626972, // Blue in red linear masking parameter - bmdDeckLinkFrameMetadataCintelLinearMaskingRedInGreen = /* 'mrig' */ 0x6D726967, // Red in green linear masking parameter - bmdDeckLinkFrameMetadataCintelLinearMaskingGreenInGreen = /* 'mgig' */ 0x6D676967, // Green in green linear masking parameter - bmdDeckLinkFrameMetadataCintelLinearMaskingBlueInGreen = /* 'mbig' */ 0x6D626967, // Blue in green linear masking parameter - bmdDeckLinkFrameMetadataCintelLinearMaskingRedInBlue = /* 'mrib' */ 0x6D726962, // Red in blue linear masking parameter - bmdDeckLinkFrameMetadataCintelLinearMaskingGreenInBlue = /* 'mgib' */ 0x6D676962, // Green in blue linear masking parameter - bmdDeckLinkFrameMetadataCintelLinearMaskingBlueInBlue = /* 'mbib' */ 0x6D626962, // Blue in blue linear masking parameter - bmdDeckLinkFrameMetadataCintelLogMaskingRedInRed = /* 'mlrr' */ 0x6D6C7272, // Red in red log masking parameter - bmdDeckLinkFrameMetadataCintelLogMaskingGreenInRed = /* 'mlgr' */ 0x6D6C6772, // Green in red log masking parameter - bmdDeckLinkFrameMetadataCintelLogMaskingBlueInRed = /* 'mlbr' */ 0x6D6C6272, // Blue in red log masking parameter - bmdDeckLinkFrameMetadataCintelLogMaskingRedInGreen = /* 'mlrg' */ 0x6D6C7267, // Red in green log masking parameter - bmdDeckLinkFrameMetadataCintelLogMaskingGreenInGreen = /* 'mlgg' */ 0x6D6C6767, // Green in green log masking parameter - bmdDeckLinkFrameMetadataCintelLogMaskingBlueInGreen = /* 'mlbg' */ 0x6D6C6267, // Blue in green log masking parameter - bmdDeckLinkFrameMetadataCintelLogMaskingRedInBlue = /* 'mlrb' */ 0x6D6C7262, // Red in blue log masking parameter - bmdDeckLinkFrameMetadataCintelLogMaskingGreenInBlue = /* 'mlgb' */ 0x6D6C6762, // Green in blue log masking parameter - bmdDeckLinkFrameMetadataCintelLogMaskingBlueInBlue = /* 'mlbb' */ 0x6D6C6262, // Blue in blue log masking parameter - bmdDeckLinkFrameMetadataCintelFilmFrameRate = /* 'cffr' */ 0x63666672, // Film frame rate + + /* HDR Metadata - Floats */ + bmdDeckLinkFrameMetadataHDRDisplayPrimariesRedX = /* 'hdrx' */ 0x68647278, // Red display primaries in range 0.0 - 1.0 bmdDeckLinkFrameMetadataHDRDisplayPrimariesRedY = /* 'hdry' */ 0x68647279, // Red display primaries in range 0.0 - 1.0 bmdDeckLinkFrameMetadataHDRDisplayPrimariesGreenX = /* 'hdgx' */ 0x68646778, // Green display primaries in range 0.0 - 1.0 @@ -424,23 +418,35 @@ enum _BMDDeckLinkFrameMetadataID { bmdDeckLinkFrameMetadataHDRMaxDisplayMasteringLuminance = /* 'hdml' */ 0x68646D6C, // Max display mastering luminance in range 1 cd/m2 - 65535 cd/m2 bmdDeckLinkFrameMetadataHDRMinDisplayMasteringLuminance = /* 'hmil' */ 0x686D696C, // Min display mastering luminance in range 0.0001 cd/m2 - 6.5535 cd/m2 bmdDeckLinkFrameMetadataHDRMaximumContentLightLevel = /* 'mcll' */ 0x6D636C6C, // Maximum Content Light Level in range 1 cd/m2 - 65535 cd/m2 - bmdDeckLinkFrameMetadataHDRMaximumFrameAverageLightLevel = /* 'fall' */ 0x66616C6C, // Maximum Frame Average Light Level in range 1 cd/m2 - 65535 cd/m2 - bmdDeckLinkFrameMetadataCintelOffsetToApplyHorizontal = /* 'otah' */ 0x6F746168, // Horizontal offset (pixels) to be applied to image - bmdDeckLinkFrameMetadataCintelOffsetToApplyVertical = /* 'otav' */ 0x6F746176, // Vertical offset (pixels) to be applied to image - bmdDeckLinkFrameMetadataCintelGainRed = /* 'LfRd' */ 0x4C665264, // Red gain parameter to apply after log - bmdDeckLinkFrameMetadataCintelGainGreen = /* 'LfGr' */ 0x4C664772, // Green gain parameter to apply after log - bmdDeckLinkFrameMetadataCintelGainBlue = /* 'LfBl' */ 0x4C66426C, // Blue gain parameter to apply after log - bmdDeckLinkFrameMetadataCintelLiftRed = /* 'GnRd' */ 0x476E5264, // Red lift parameter to apply after log and gain - bmdDeckLinkFrameMetadataCintelLiftGreen = /* 'GnGr' */ 0x476E4772, // Green lift parameter to apply after log and gain - bmdDeckLinkFrameMetadataCintelLiftBlue = /* 'GnBl' */ 0x476E426C // Blue lift parameter to apply after log and gain + bmdDeckLinkFrameMetadataHDRMaximumFrameAverageLightLevel = /* 'fall' */ 0x66616C6C // Maximum Frame Average Light Level in range 1 cd/m2 - 65535 cd/m2 }; -/* Enum BMDDuplexMode - Duplex for configurable ports */ +/* Enum BMDProfileID - Identifies a profile */ -typedef uint32_t BMDDuplexMode; -enum _BMDDuplexMode { - bmdDuplexModeFull = /* 'fdup' */ 0x66647570, - bmdDuplexModeHalf = /* 'hdup' */ 0x68647570 +typedef uint32_t BMDProfileID; +enum _BMDProfileID { + bmdProfileOneSubDeviceFullDuplex = /* '1dfd' */ 0x31646664, + bmdProfileOneSubDeviceHalfDuplex = /* '1dhd' */ 0x31646864, + bmdProfileTwoSubDevicesFullDuplex = /* '2dfd' */ 0x32646664, + bmdProfileTwoSubDevicesHalfDuplex = /* '2dhd' */ 0x32646864, + bmdProfileFourSubDevicesHalfDuplex = /* '4dhd' */ 0x34646864 +}; + +/* Enum BMDHDMITimecodePacking - Packing form of timecode on HDMI */ + +typedef uint32_t BMDHDMITimecodePacking; +enum _BMDHDMITimecodePacking { + bmdHDMITimecodePackingIEEEOUI000085 = 0x00008500, + bmdHDMITimecodePackingIEEEOUI080046 = 0x08004601, + bmdHDMITimecodePackingIEEEOUI5CF9F0 = 0x5CF9F003 +}; + +/* Enum BMDInternalKeyingAncillaryDataSource - Source for VANC and timecode data when performing internal keying */ + +typedef uint32_t BMDInternalKeyingAncillaryDataSource; +enum _BMDInternalKeyingAncillaryDataSource { + bmdInternalKeyingUsesAncillaryDataFromInputSignal = /* 'ikai' */ 0x696B6169, + bmdInternalKeyingUsesAncillaryDataFromKeyFrame = /* 'ikak' */ 0x696B616B }; /* Enum BMDDeckLinkAttributeID - DeckLink Attribute ID */ @@ -452,7 +458,6 @@ enum _BMDDeckLinkAttributeID { BMDDeckLinkSupportsInternalKeying = /* 'keyi' */ 0x6B657969, BMDDeckLinkSupportsExternalKeying = /* 'keye' */ 0x6B657965, - BMDDeckLinkSupportsHDKeying = /* 'keyh' */ 0x6B657968, BMDDeckLinkSupportsInputFormatDetection = /* 'infd' */ 0x696E6664, BMDDeckLinkHasReferenceInput = /* 'hrin' */ 0x6872696E, BMDDeckLinkHasSerialPort = /* 'hspt' */ 0x68737074, @@ -461,16 +466,20 @@ enum _BMDDeckLinkAttributeID { BMDDeckLinkHasVideoInputAntiAliasingFilter = /* 'aafl' */ 0x6161666C, BMDDeckLinkHasBypass = /* 'byps' */ 0x62797073, BMDDeckLinkSupportsClockTimingAdjustment = /* 'ctad' */ 0x63746164, - BMDDeckLinkSupportsFullDuplex = /* 'fdup' */ 0x66647570, BMDDeckLinkSupportsFullFrameReferenceInputTimingOffset = /* 'frin' */ 0x6672696E, BMDDeckLinkSupportsSMPTELevelAOutput = /* 'lvla' */ 0x6C766C61, + BMDDeckLinkSupportsAutoSwitchingPPsFOnInput = /* 'apsf' */ 0x61707366, BMDDeckLinkSupportsDualLinkSDI = /* 'sdls' */ 0x73646C73, BMDDeckLinkSupportsQuadLinkSDI = /* 'sqls' */ 0x73716C73, BMDDeckLinkSupportsIdleOutput = /* 'idou' */ 0x69646F75, + BMDDeckLinkVANCRequires10BitYUVVideoFrames = /* 'vioY' */ 0x76696F59, // Legacy product requires v210 active picture for IDeckLinkVideoFrameAncillaryPackets or 10-bit VANC BMDDeckLinkHasLTCTimecodeInput = /* 'hltc' */ 0x686C7463, - BMDDeckLinkSupportsDuplexModeConfiguration = /* 'dupx' */ 0x64757078, BMDDeckLinkSupportsHDRMetadata = /* 'hdrm' */ 0x6864726D, BMDDeckLinkSupportsColorspaceMetadata = /* 'cmet' */ 0x636D6574, + BMDDeckLinkSupportsHDMITimecode = /* 'htim' */ 0x6874696D, + BMDDeckLinkSupportsHighFrameRateTimecode = /* 'HFRT' */ 0x48465254, + BMDDeckLinkSupportsSynchronizeToCaptureGroup = /* 'stcg' */ 0x73746367, + BMDDeckLinkSupportsSynchronizeToPlaybackGroup = /* 'stpg' */ 0x73747067, /* Integers */ @@ -493,7 +502,10 @@ enum _BMDDeckLinkAttributeID { BMDDeckLinkAudioInputXLRChannelCount = /* 'aixc' */ 0x61697863, BMDDeckLinkAudioOutputRCAChannelCount = /* 'aorc' */ 0x616F7263, BMDDeckLinkAudioOutputXLRChannelCount = /* 'aoxc' */ 0x616F7863, - BMDDeckLinkPairedDevicePersistentID = /* 'ppid' */ 0x70706964, + BMDDeckLinkProfileID = /* 'prid' */ 0x70726964, // Returns a BMDProfileID + BMDDeckLinkDuplex = /* 'dupx' */ 0x64757078, + BMDDeckLinkMinimumPrerollFrames = /* 'mprf' */ 0x6D707266, + BMDDeckLinkSupportedDynamicRange = /* 'sudr' */ 0x73756472, /* Floats */ @@ -517,6 +529,9 @@ enum _BMDDeckLinkAttributeID { typedef uint32_t BMDDeckLinkAPIInformationID; enum _BMDDeckLinkAPIInformationID { + + /* Integer or String */ + BMDDeckLinkAPIVersion = /* 'vers' */ 0x76657273 }; @@ -528,7 +543,11 @@ enum _BMDDeckLinkStatusID { /* Integers */ bmdDeckLinkStatusDetectedVideoInputMode = /* 'dvim' */ 0x6476696D, - bmdDeckLinkStatusDetectedVideoInputFlags = /* 'dvif' */ 0x64766966, + bmdDeckLinkStatusDetectedVideoInputFormatFlags = /* 'dvff' */ 0x64766666, + bmdDeckLinkStatusDetectedVideoInputFieldDominance = /* 'dvfd' */ 0x64766664, + bmdDeckLinkStatusDetectedVideoInputColorspace = /* 'dscl' */ 0x6473636C, + bmdDeckLinkStatusDetectedVideoInputDynamicRange = /* 'dsdr' */ 0x64736472, + bmdDeckLinkStatusDetectedSDILinkConfiguration = /* 'dslc' */ 0x64736C63, bmdDeckLinkStatusCurrentVideoInputMode = /* 'cvim' */ 0x6376696D, bmdDeckLinkStatusCurrentVideoInputPixelFormat = /* 'cvip' */ 0x63766970, bmdDeckLinkStatusCurrentVideoInputFlags = /* 'cvif' */ 0x63766966, @@ -539,7 +558,6 @@ enum _BMDDeckLinkStatusID { bmdDeckLinkStatusLastVideoOutputPixelFormat = /* 'opix' */ 0x6F706978, bmdDeckLinkStatusReferenceSignalMode = /* 'refm' */ 0x7265666D, bmdDeckLinkStatusReferenceSignalFlags = /* 'reff' */ 0x72656666, - bmdDeckLinkStatusDuplexMode = /* 'dupx' */ 0x64757078, bmdDeckLinkStatusBusy = /* 'busy' */ 0x62757379, bmdDeckLinkStatusInterchangeablePanelType = /* 'icpt' */ 0x69637074, bmdDeckLinkStatusDeviceTemperature = /* 'dtmp' */ 0x64746D70, @@ -548,6 +566,9 @@ enum _BMDDeckLinkStatusID { bmdDeckLinkStatusVideoInputSignalLocked = /* 'visl' */ 0x7669736C, bmdDeckLinkStatusReferenceSignalLocked = /* 'refl' */ 0x7265666C, + + /* Bytes */ + bmdDeckLinkStatusReceivedEDID = /* 'edid' */ 0x65646964 }; @@ -559,14 +580,14 @@ enum _BMDDeckLinkVideoStatusFlags { bmdDeckLinkVideoStatusDualStream3D = 1 << 1 }; -/* Enum BMDDuplexStatus - Duplex status of the device */ +/* Enum BMDDuplexMode - Duplex of the device */ -typedef uint32_t BMDDuplexStatus; -enum _BMDDuplexStatus { - bmdDuplexStatusFullDuplex = /* 'fdup' */ 0x66647570, - bmdDuplexStatusHalfDuplex = /* 'hdup' */ 0x68647570, - bmdDuplexStatusSimplex = /* 'splx' */ 0x73706C78, - bmdDuplexStatusInactive = /* 'inac' */ 0x696E6163 +typedef uint32_t BMDDuplexMode; +enum _BMDDuplexMode { + bmdDuplexFull = /* 'dxfu' */ 0x64786675, + bmdDuplexHalf = /* 'dxha' */ 0x64786861, + bmdDuplexSimplex = /* 'dxsp' */ 0x64787370, + bmdDuplexInactive = /* 'dxin' */ 0x6478696E }; /* Enum BMDPanelType - The type of interchangeable panel */ @@ -646,7 +667,11 @@ class IDeckLinkScreenPreviewCallback; class IDeckLinkGLScreenPreviewHelper; class IDeckLinkNotificationCallback; class IDeckLinkNotification; -class IDeckLinkAttributes; +class IDeckLinkProfileAttributes; +class IDeckLinkProfileIterator; +class IDeckLinkProfile; +class IDeckLinkProfileCallback; +class IDeckLinkProfileManager; class IDeckLinkStatus; class IDeckLinkKeyer; class IDeckLinkVideoConversion; @@ -658,7 +683,7 @@ class IDeckLinkDiscovery; class BMD_PUBLIC IDeckLinkVideoOutputCallback : public IUnknown { public: - virtual HRESULT ScheduledFrameCompleted (/* in */ IDeckLinkVideoFrame *completedFrame, /* in */ BMDOutputFrameCompletionResult result) = 0; + virtual HRESULT ScheduledFrameCompleted (/* in */ IDeckLinkVideoFrame* completedFrame, /* in */ BMDOutputFrameCompletionResult result) = 0; virtual HRESULT ScheduledPlaybackHasStopped (void) = 0; protected: @@ -670,7 +695,7 @@ protected: class BMD_PUBLIC IDeckLinkInputCallback : public IUnknown { public: - virtual HRESULT VideoInputFormatChanged (/* in */ BMDVideoInputFormatChangedEvents notificationEvents, /* in */ IDeckLinkDisplayMode *newDisplayMode, /* in */ BMDDetectedVideoInputFormatFlags detectedSignalFlags) = 0; + virtual HRESULT VideoInputFormatChanged (/* in */ BMDVideoInputFormatChangedEvents notificationEvents, /* in */ IDeckLinkDisplayMode* newDisplayMode, /* in */ BMDDetectedVideoInputFormatFlags detectedSignalFlags) = 0; virtual HRESULT VideoInputFrameArrived (/* in */ IDeckLinkVideoInputFrame* videoFrame, /* in */ IDeckLinkAudioInputPacket* audioPacket) = 0; protected: @@ -682,7 +707,7 @@ protected: class BMD_PUBLIC IDeckLinkEncoderInputCallback : public IUnknown { public: - virtual HRESULT VideoInputSignalChanged (/* in */ BMDVideoInputFormatChangedEvents notificationEvents, /* in */ IDeckLinkDisplayMode *newDisplayMode, /* in */ BMDDetectedVideoInputFormatFlags detectedSignalFlags) = 0; + virtual HRESULT VideoInputSignalChanged (/* in */ BMDVideoInputFormatChangedEvents notificationEvents, /* in */ IDeckLinkDisplayMode* newDisplayMode, /* in */ BMDDetectedVideoInputFormatFlags detectedSignalFlags) = 0; virtual HRESULT VideoPacketArrived (/* in */ IDeckLinkEncoderVideoPacket* videoPacket) = 0; virtual HRESULT AudioPacketArrived (/* in */ IDeckLinkEncoderAudioPacket* audioPacket) = 0; @@ -695,9 +720,8 @@ protected: class BMD_PUBLIC IDeckLinkMemoryAllocator : public IUnknown { public: - virtual HRESULT AllocateBuffer (/* in */ uint32_t bufferSize, /* out */ void **allocatedBuffer) = 0; - virtual HRESULT ReleaseBuffer (/* in */ void *buffer) = 0; - + virtual HRESULT AllocateBuffer (/* in */ uint32_t bufferSize, /* out */ void** allocatedBuffer) = 0; + virtual HRESULT ReleaseBuffer (/* in */ void* buffer) = 0; virtual HRESULT Commit (void) = 0; virtual HRESULT Decommit (void) = 0; }; @@ -710,12 +734,12 @@ public: virtual HRESULT RenderAudioSamples (/* in */ bool preroll) = 0; }; -/* Interface IDeckLinkIterator - enumerates installed DeckLink hardware */ +/* Interface IDeckLinkIterator - Enumerates installed DeckLink hardware */ class BMD_PUBLIC IDeckLinkIterator : public IUnknown { public: - virtual HRESULT Next (/* out */ IDeckLink **deckLinkInstance) = 0; + virtual HRESULT Next (/* out */ IDeckLink** deckLinkInstance) = 0; }; /* Interface IDeckLinkAPIInformation - DeckLinkAPI attribute interface */ @@ -723,10 +747,10 @@ public: class BMD_PUBLIC IDeckLinkAPIInformation : public IUnknown { public: - virtual HRESULT GetFlag (/* in */ BMDDeckLinkAPIInformationID cfgID, /* out */ bool *value) = 0; - virtual HRESULT GetInt (/* in */ BMDDeckLinkAPIInformationID cfgID, /* out */ int64_t *value) = 0; - virtual HRESULT GetFloat (/* in */ BMDDeckLinkAPIInformationID cfgID, /* out */ double *value) = 0; - virtual HRESULT GetString (/* in */ BMDDeckLinkAPIInformationID cfgID, /* out */ const char **value) = 0; + virtual HRESULT GetFlag (/* in */ BMDDeckLinkAPIInformationID cfgID, /* out */ bool* value) = 0; + virtual HRESULT GetInt (/* in */ BMDDeckLinkAPIInformationID cfgID, /* out */ int64_t* value) = 0; + virtual HRESULT GetFloat (/* in */ BMDDeckLinkAPIInformationID cfgID, /* out */ double* value) = 0; + virtual HRESULT GetString (/* in */ BMDDeckLinkAPIInformationID cfgID, /* out */ const char** value) = 0; protected: virtual ~IDeckLinkAPIInformation () {} // call Release method to drop reference count @@ -737,53 +761,47 @@ protected: class BMD_PUBLIC IDeckLinkOutput : public IUnknown { public: - virtual HRESULT DoesSupportVideoMode (/* in */ BMDDisplayMode displayMode, /* in */ BMDPixelFormat pixelFormat, /* in */ BMDVideoOutputFlags flags, /* out */ BMDDisplayModeSupport *result, /* out */ IDeckLinkDisplayMode **resultDisplayMode) = 0; - virtual HRESULT GetDisplayModeIterator (/* out */ IDeckLinkDisplayModeIterator **iterator) = 0; - - virtual HRESULT SetScreenPreviewCallback (/* in */ IDeckLinkScreenPreviewCallback *previewCallback) = 0; + virtual HRESULT DoesSupportVideoMode (/* in */ BMDVideoConnection connection /* If a value of bmdVideoConnectionUnspecified is specified, the caller does not care about the connection */, /* in */ BMDDisplayMode requestedMode, /* in */ BMDPixelFormat requestedPixelFormat, /* in */ BMDVideoOutputConversionMode conversionMode, /* in */ BMDSupportedVideoModeFlags flags, /* out */ BMDDisplayMode* actualMode, /* out */ bool* supported) = 0; + virtual HRESULT GetDisplayMode (/* in */ BMDDisplayMode displayMode, /* out */ IDeckLinkDisplayMode** resultDisplayMode) = 0; + virtual HRESULT GetDisplayModeIterator (/* out */ IDeckLinkDisplayModeIterator** iterator) = 0; + virtual HRESULT SetScreenPreviewCallback (/* in */ IDeckLinkScreenPreviewCallback* previewCallback) = 0; /* Video Output */ virtual HRESULT EnableVideoOutput (/* in */ BMDDisplayMode displayMode, /* in */ BMDVideoOutputFlags flags) = 0; virtual HRESULT DisableVideoOutput (void) = 0; - - virtual HRESULT SetVideoOutputFrameMemoryAllocator (/* in */ IDeckLinkMemoryAllocator *theAllocator) = 0; - virtual HRESULT CreateVideoFrame (/* in */ int32_t width, /* in */ int32_t height, /* in */ int32_t rowBytes, /* in */ BMDPixelFormat pixelFormat, /* in */ BMDFrameFlags flags, /* out */ IDeckLinkMutableVideoFrame **outFrame) = 0; - virtual HRESULT CreateAncillaryData (/* in */ BMDPixelFormat pixelFormat, /* out */ IDeckLinkVideoFrameAncillary **outBuffer) = 0; // Use of IDeckLinkVideoFrameAncillaryPackets is preferred - - virtual HRESULT DisplayVideoFrameSync (/* in */ IDeckLinkVideoFrame *theFrame) = 0; - virtual HRESULT ScheduleVideoFrame (/* in */ IDeckLinkVideoFrame *theFrame, /* in */ BMDTimeValue displayTime, /* in */ BMDTimeValue displayDuration, /* in */ BMDTimeScale timeScale) = 0; - virtual HRESULT SetScheduledFrameCompletionCallback (/* in */ IDeckLinkVideoOutputCallback *theCallback) = 0; - virtual HRESULT GetBufferedVideoFrameCount (/* out */ uint32_t *bufferedFrameCount) = 0; + virtual HRESULT SetVideoOutputFrameMemoryAllocator (/* in */ IDeckLinkMemoryAllocator* theAllocator) = 0; + virtual HRESULT CreateVideoFrame (/* in */ int32_t width, /* in */ int32_t height, /* in */ int32_t rowBytes, /* in */ BMDPixelFormat pixelFormat, /* in */ BMDFrameFlags flags, /* out */ IDeckLinkMutableVideoFrame** outFrame) = 0; + virtual HRESULT CreateAncillaryData (/* in */ BMDPixelFormat pixelFormat, /* out */ IDeckLinkVideoFrameAncillary** outBuffer) = 0; // Use of IDeckLinkVideoFrameAncillaryPackets is preferred + virtual HRESULT DisplayVideoFrameSync (/* in */ IDeckLinkVideoFrame* theFrame) = 0; + virtual HRESULT ScheduleVideoFrame (/* in */ IDeckLinkVideoFrame* theFrame, /* in */ BMDTimeValue displayTime, /* in */ BMDTimeValue displayDuration, /* in */ BMDTimeScale timeScale) = 0; + virtual HRESULT SetScheduledFrameCompletionCallback (/* in */ IDeckLinkVideoOutputCallback* theCallback) = 0; + virtual HRESULT GetBufferedVideoFrameCount (/* out */ uint32_t* bufferedFrameCount) = 0; /* Audio Output */ virtual HRESULT EnableAudioOutput (/* in */ BMDAudioSampleRate sampleRate, /* in */ BMDAudioSampleType sampleType, /* in */ uint32_t channelCount, /* in */ BMDAudioOutputStreamType streamType) = 0; virtual HRESULT DisableAudioOutput (void) = 0; - - virtual HRESULT WriteAudioSamplesSync (/* in */ void *buffer, /* in */ uint32_t sampleFrameCount, /* out */ uint32_t *sampleFramesWritten) = 0; - + virtual HRESULT WriteAudioSamplesSync (/* in */ void* buffer, /* in */ uint32_t sampleFrameCount, /* out */ uint32_t* sampleFramesWritten) = 0; virtual HRESULT BeginAudioPreroll (void) = 0; virtual HRESULT EndAudioPreroll (void) = 0; - virtual HRESULT ScheduleAudioSamples (/* in */ void *buffer, /* in */ uint32_t sampleFrameCount, /* in */ BMDTimeValue streamTime, /* in */ BMDTimeScale timeScale, /* out */ uint32_t *sampleFramesWritten) = 0; - - virtual HRESULT GetBufferedAudioSampleFrameCount (/* out */ uint32_t *bufferedSampleFrameCount) = 0; + virtual HRESULT ScheduleAudioSamples (/* in */ void* buffer, /* in */ uint32_t sampleFrameCount, /* in */ BMDTimeValue streamTime, /* in */ BMDTimeScale timeScale, /* out */ uint32_t* sampleFramesWritten) = 0; + virtual HRESULT GetBufferedAudioSampleFrameCount (/* out */ uint32_t* bufferedSampleFrameCount) = 0; virtual HRESULT FlushBufferedAudioSamples (void) = 0; - - virtual HRESULT SetAudioCallback (/* in */ IDeckLinkAudioOutputCallback *theCallback) = 0; + virtual HRESULT SetAudioCallback (/* in */ IDeckLinkAudioOutputCallback* theCallback) = 0; /* Output Control */ virtual HRESULT StartScheduledPlayback (/* in */ BMDTimeValue playbackStartTime, /* in */ BMDTimeScale timeScale, /* in */ double playbackSpeed) = 0; - virtual HRESULT StopScheduledPlayback (/* in */ BMDTimeValue stopPlaybackAtTime, /* out */ BMDTimeValue *actualStopTime, /* in */ BMDTimeScale timeScale) = 0; - virtual HRESULT IsScheduledPlaybackRunning (/* out */ bool *active) = 0; - virtual HRESULT GetScheduledStreamTime (/* in */ BMDTimeScale desiredTimeScale, /* out */ BMDTimeValue *streamTime, /* out */ double *playbackSpeed) = 0; - virtual HRESULT GetReferenceStatus (/* out */ BMDReferenceStatus *referenceStatus) = 0; + virtual HRESULT StopScheduledPlayback (/* in */ BMDTimeValue stopPlaybackAtTime, /* out */ BMDTimeValue* actualStopTime, /* in */ BMDTimeScale timeScale) = 0; + virtual HRESULT IsScheduledPlaybackRunning (/* out */ bool* active) = 0; + virtual HRESULT GetScheduledStreamTime (/* in */ BMDTimeScale desiredTimeScale, /* out */ BMDTimeValue* streamTime, /* out */ double* playbackSpeed) = 0; + virtual HRESULT GetReferenceStatus (/* out */ BMDReferenceStatus* referenceStatus) = 0; /* Hardware Timing */ - virtual HRESULT GetHardwareReferenceClock (/* in */ BMDTimeScale desiredTimeScale, /* out */ BMDTimeValue *hardwareTime, /* out */ BMDTimeValue *timeInFrame, /* out */ BMDTimeValue *ticksPerFrame) = 0; - virtual HRESULT GetFrameCompletionReferenceTimestamp (/* in */ IDeckLinkVideoFrame *theFrame, /* in */ BMDTimeScale desiredTimeScale, /* out */ BMDTimeValue *frameCompletionTimestamp) = 0; + virtual HRESULT GetHardwareReferenceClock (/* in */ BMDTimeScale desiredTimeScale, /* out */ BMDTimeValue* hardwareTime, /* out */ BMDTimeValue* timeInFrame, /* out */ BMDTimeValue* ticksPerFrame) = 0; + virtual HRESULT GetFrameCompletionReferenceTimestamp (/* in */ IDeckLinkVideoFrame* theFrame, /* in */ BMDTimeScale desiredTimeScale, /* out */ BMDTimeValue* frameCompletionTimestamp) = 0; protected: virtual ~IDeckLinkOutput () {} // call Release method to drop reference count @@ -794,23 +812,23 @@ protected: class BMD_PUBLIC IDeckLinkInput : public IUnknown { public: - virtual HRESULT DoesSupportVideoMode (/* in */ BMDDisplayMode displayMode, /* in */ BMDPixelFormat pixelFormat, /* in */ BMDVideoInputFlags flags, /* out */ BMDDisplayModeSupport *result, /* out */ IDeckLinkDisplayMode **resultDisplayMode) = 0; - virtual HRESULT GetDisplayModeIterator (/* out */ IDeckLinkDisplayModeIterator **iterator) = 0; - - virtual HRESULT SetScreenPreviewCallback (/* in */ IDeckLinkScreenPreviewCallback *previewCallback) = 0; + virtual HRESULT DoesSupportVideoMode (/* in */ BMDVideoConnection connection /* If a value of bmdVideoConnectionUnspecified is specified, the caller does not care about the connection */, /* in */ BMDDisplayMode requestedMode, /* in */ BMDPixelFormat requestedPixelFormat, /* in */ BMDVideoInputConversionMode conversionMode, /* in */ BMDSupportedVideoModeFlags flags, /* out */ BMDDisplayMode* actualMode, /* out */ bool* supported) = 0; + virtual HRESULT GetDisplayMode (/* in */ BMDDisplayMode displayMode, /* out */ IDeckLinkDisplayMode** resultDisplayMode) = 0; + virtual HRESULT GetDisplayModeIterator (/* out */ IDeckLinkDisplayModeIterator** iterator) = 0; + virtual HRESULT SetScreenPreviewCallback (/* in */ IDeckLinkScreenPreviewCallback* previewCallback) = 0; /* Video Input */ virtual HRESULT EnableVideoInput (/* in */ BMDDisplayMode displayMode, /* in */ BMDPixelFormat pixelFormat, /* in */ BMDVideoInputFlags flags) = 0; virtual HRESULT DisableVideoInput (void) = 0; - virtual HRESULT GetAvailableVideoFrameCount (/* out */ uint32_t *availableFrameCount) = 0; - virtual HRESULT SetVideoInputFrameMemoryAllocator (/* in */ IDeckLinkMemoryAllocator *theAllocator) = 0; + virtual HRESULT GetAvailableVideoFrameCount (/* out */ uint32_t* availableFrameCount) = 0; + virtual HRESULT SetVideoInputFrameMemoryAllocator (/* in */ IDeckLinkMemoryAllocator* theAllocator) = 0; /* Audio Input */ virtual HRESULT EnableAudioInput (/* in */ BMDAudioSampleRate sampleRate, /* in */ BMDAudioSampleType sampleType, /* in */ uint32_t channelCount) = 0; virtual HRESULT DisableAudioInput (void) = 0; - virtual HRESULT GetAvailableAudioSampleFrameCount (/* out */ uint32_t *availableSampleFrameCount) = 0; + virtual HRESULT GetAvailableAudioSampleFrameCount (/* out */ uint32_t* availableSampleFrameCount) = 0; /* Input Control */ @@ -818,11 +836,11 @@ public: virtual HRESULT StopStreams (void) = 0; virtual HRESULT PauseStreams (void) = 0; virtual HRESULT FlushStreams (void) = 0; - virtual HRESULT SetCallback (/* in */ IDeckLinkInputCallback *theCallback) = 0; + virtual HRESULT SetCallback (/* in */ IDeckLinkInputCallback* theCallback) = 0; /* Hardware Timing */ - virtual HRESULT GetHardwareReferenceClock (/* in */ BMDTimeScale desiredTimeScale, /* out */ BMDTimeValue *hardwareTime, /* out */ BMDTimeValue *timeInFrame, /* out */ BMDTimeValue *ticksPerFrame) = 0; + virtual HRESULT GetHardwareReferenceClock (/* in */ BMDTimeScale desiredTimeScale, /* out */ BMDTimeValue* hardwareTime, /* out */ BMDTimeValue* timeInFrame, /* out */ BMDTimeValue* ticksPerFrame) = 0; protected: virtual ~IDeckLinkInput () {} // call Release method to drop reference count @@ -834,7 +852,7 @@ class BMD_PUBLIC IDeckLinkHDMIInputEDID : public IUnknown { public: virtual HRESULT SetInt (/* in */ BMDDeckLinkHDMIInputEDIDID cfgID, /* in */ int64_t value) = 0; - virtual HRESULT GetInt (/* in */ BMDDeckLinkHDMIInputEDIDID cfgID, /* out */ int64_t *value) = 0; + virtual HRESULT GetInt (/* in */ BMDDeckLinkHDMIInputEDIDID cfgID, /* out */ int64_t* value) = 0; virtual HRESULT WriteToEDID (void) = 0; protected: @@ -846,21 +864,22 @@ protected: class BMD_PUBLIC IDeckLinkEncoderInput : public IUnknown { public: - virtual HRESULT DoesSupportVideoMode (/* in */ BMDDisplayMode displayMode, /* in */ BMDPixelFormat pixelFormat, /* in */ BMDVideoInputFlags flags, /* out */ BMDDisplayModeSupport *result, /* out */ IDeckLinkDisplayMode **resultDisplayMode) = 0; - virtual HRESULT GetDisplayModeIterator (/* out */ IDeckLinkDisplayModeIterator **iterator) = 0; + virtual HRESULT DoesSupportVideoMode (/* in */ BMDVideoConnection connection /* If a value of bmdVideoConnectionUnspecified is specified, the caller does not care about the connection */, /* in */ BMDDisplayMode requestedMode, /* in */ BMDPixelFormat requestedCodec, /* in */ uint32_t requestedCodecProfile, /* in */ BMDSupportedVideoModeFlags flags, /* out */ bool* supported) = 0; + virtual HRESULT GetDisplayMode (/* in */ BMDDisplayMode displayMode, /* out */ IDeckLinkDisplayMode** resultDisplayMode) = 0; + virtual HRESULT GetDisplayModeIterator (/* out */ IDeckLinkDisplayModeIterator** iterator) = 0; /* Video Input */ virtual HRESULT EnableVideoInput (/* in */ BMDDisplayMode displayMode, /* in */ BMDPixelFormat pixelFormat, /* in */ BMDVideoInputFlags flags) = 0; virtual HRESULT DisableVideoInput (void) = 0; - virtual HRESULT GetAvailablePacketsCount (/* out */ uint32_t *availablePacketsCount) = 0; - virtual HRESULT SetMemoryAllocator (/* in */ IDeckLinkMemoryAllocator *theAllocator) = 0; + virtual HRESULT GetAvailablePacketsCount (/* out */ uint32_t* availablePacketsCount) = 0; + virtual HRESULT SetMemoryAllocator (/* in */ IDeckLinkMemoryAllocator* theAllocator) = 0; /* Audio Input */ virtual HRESULT EnableAudioInput (/* in */ BMDAudioFormat audioFormat, /* in */ BMDAudioSampleRate sampleRate, /* in */ BMDAudioSampleType sampleType, /* in */ uint32_t channelCount) = 0; virtual HRESULT DisableAudioInput (void) = 0; - virtual HRESULT GetAvailableAudioSampleFrameCount (/* out */ uint32_t *availableSampleFrameCount) = 0; + virtual HRESULT GetAvailableAudioSampleFrameCount (/* out */ uint32_t* availableSampleFrameCount) = 0; /* Input Control */ @@ -868,11 +887,11 @@ public: virtual HRESULT StopStreams (void) = 0; virtual HRESULT PauseStreams (void) = 0; virtual HRESULT FlushStreams (void) = 0; - virtual HRESULT SetCallback (/* in */ IDeckLinkEncoderInputCallback *theCallback) = 0; + virtual HRESULT SetCallback (/* in */ IDeckLinkEncoderInputCallback* theCallback) = 0; /* Hardware Timing */ - virtual HRESULT GetHardwareReferenceClock (/* in */ BMDTimeScale desiredTimeScale, /* out */ BMDTimeValue *hardwareTime, /* out */ BMDTimeValue *timeInFrame, /* out */ BMDTimeValue *ticksPerFrame) = 0; + virtual HRESULT GetHardwareReferenceClock (/* in */ BMDTimeScale desiredTimeScale, /* out */ BMDTimeValue* hardwareTime, /* out */ BMDTimeValue* timeInFrame, /* out */ BMDTimeValue* ticksPerFrame) = 0; protected: virtual ~IDeckLinkEncoderInput () {} // call Release method to drop reference count @@ -888,10 +907,9 @@ public: virtual long GetRowBytes (void) = 0; virtual BMDPixelFormat GetPixelFormat (void) = 0; virtual BMDFrameFlags GetFlags (void) = 0; - virtual HRESULT GetBytes (/* out */ void **buffer) = 0; - - virtual HRESULT GetTimecode (/* in */ BMDTimecodeFormat format, /* out */ IDeckLinkTimecode **timecode) = 0; - virtual HRESULT GetAncillaryData (/* out */ IDeckLinkVideoFrameAncillary **ancillary) = 0; // Use of IDeckLinkVideoFrameAncillaryPackets is preferred + virtual HRESULT GetBytes (/* out */ void** buffer) = 0; + virtual HRESULT GetTimecode (/* in */ BMDTimecodeFormat format, /* out */ IDeckLinkTimecode** timecode) = 0; + virtual HRESULT GetAncillaryData (/* out */ IDeckLinkVideoFrameAncillary** ancillary) = 0; // Use of IDeckLinkVideoFrameAncillaryPackets is preferred protected: virtual ~IDeckLinkVideoFrame () {} // call Release method to drop reference count @@ -903,10 +921,9 @@ class BMD_PUBLIC IDeckLinkMutableVideoFrame : public IDeckLinkVideoFrame { public: virtual HRESULT SetFlags (/* in */ BMDFrameFlags newFlags) = 0; - - virtual HRESULT SetTimecode (/* in */ BMDTimecodeFormat format, /* in */ IDeckLinkTimecode *timecode) = 0; + virtual HRESULT SetTimecode (/* in */ BMDTimecodeFormat format, /* in */ IDeckLinkTimecode* timecode) = 0; virtual HRESULT SetTimecodeFromComponents (/* in */ BMDTimecodeFormat format, /* in */ uint8_t hours, /* in */ uint8_t minutes, /* in */ uint8_t seconds, /* in */ uint8_t frames, /* in */ BMDTimecodeFlags flags) = 0; - virtual HRESULT SetAncillaryData (/* in */ IDeckLinkVideoFrameAncillary *ancillary) = 0; + virtual HRESULT SetAncillaryData (/* in */ IDeckLinkVideoFrameAncillary* ancillary) = 0; virtual HRESULT SetTimecodeUserBits (/* in */ BMDTimecodeFormat format, /* in */ BMDTimecodeUserBits userBits) = 0; protected: @@ -919,21 +936,22 @@ class BMD_PUBLIC IDeckLinkVideoFrame3DExtensions : public IUnknown { public: virtual BMDVideo3DPackingFormat Get3DPackingFormat (void) = 0; - virtual HRESULT GetFrameForRightEye (/* out */ IDeckLinkVideoFrame* *rightEyeFrame) = 0; + virtual HRESULT GetFrameForRightEye (/* out */ IDeckLinkVideoFrame** rightEyeFrame) = 0; protected: virtual ~IDeckLinkVideoFrame3DExtensions () {} // call Release method to drop reference count }; -/* Interface IDeckLinkVideoFrameMetadataExtensions - Optional interface implemented on IDeckLinkVideoFrame to support frame metadata such as HDMI HDR information */ +/* Interface IDeckLinkVideoFrameMetadataExtensions - Optional interface implemented on IDeckLinkVideoFrame to support frame metadata such as HDR information */ class BMD_PUBLIC IDeckLinkVideoFrameMetadataExtensions : public IUnknown { public: - virtual HRESULT GetInt (/* in */ BMDDeckLinkFrameMetadataID metadataID, /* out */ int64_t *value) = 0; - virtual HRESULT GetFloat (/* in */ BMDDeckLinkFrameMetadataID metadataID, /* out */ double *value) = 0; + virtual HRESULT GetInt (/* in */ BMDDeckLinkFrameMetadataID metadataID, /* out */ int64_t* value) = 0; + virtual HRESULT GetFloat (/* in */ BMDDeckLinkFrameMetadataID metadataID, /* out */ double* value) = 0; virtual HRESULT GetFlag (/* in */ BMDDeckLinkFrameMetadataID metadataID, /* out */ bool* value) = 0; - virtual HRESULT GetString (/* in */ BMDDeckLinkFrameMetadataID metadataID, /* out */ const char **value) = 0; + virtual HRESULT GetString (/* in */ BMDDeckLinkFrameMetadataID metadataID, /* out */ const char** value) = 0; + virtual HRESULT GetBytes (/* in */ BMDDeckLinkFrameMetadataID metadataID, /* out */ void* buffer /* optional */, /* in, out */ uint32_t* bufferSize) = 0; protected: virtual ~IDeckLinkVideoFrameMetadataExtensions () {} // call Release method to drop reference count @@ -944,8 +962,8 @@ protected: class BMD_PUBLIC IDeckLinkVideoInputFrame : public IDeckLinkVideoFrame { public: - virtual HRESULT GetStreamTime (/* out */ BMDTimeValue *frameTime, /* out */ BMDTimeValue *frameDuration, /* in */ BMDTimeScale timeScale) = 0; - virtual HRESULT GetHardwareReferenceTimestamp (/* in */ BMDTimeScale timeScale, /* out */ BMDTimeValue *frameTime, /* out */ BMDTimeValue *frameDuration) = 0; + virtual HRESULT GetStreamTime (/* out */ BMDTimeValue* frameTime, /* out */ BMDTimeValue* frameDuration, /* in */ BMDTimeScale timeScale) = 0; + virtual HRESULT GetHardwareReferenceTimestamp (/* in */ BMDTimeScale timeScale, /* out */ BMDTimeValue* frameTime, /* out */ BMDTimeValue* frameDuration) = 0; protected: virtual ~IDeckLinkVideoInputFrame () {} // call Release method to drop reference count @@ -956,12 +974,11 @@ protected: class BMD_PUBLIC IDeckLinkAncillaryPacket : public IUnknown { public: - - virtual HRESULT GetBytes (/* in */ BMDAncillaryPacketFormat format /* For output, only one format need be offered */, /* out */ const void **data /* Optional */, /* out */ uint32_t *size /* Optional */) = 0; + virtual HRESULT GetBytes (/* in */ BMDAncillaryPacketFormat format /* For output, only one format need be offered */, /* out */ const void** data /* Optional */, /* out */ uint32_t* size /* Optional */) = 0; virtual uint8_t GetDID (void) = 0; virtual uint8_t GetSDID (void) = 0; - virtual uint32_t GetLineNumber (void) = 0; // On output, zero is auto - virtual uint8_t GetDataStreamIndex (void) = 0; // Usually zero. Can only be 1 if non-SD and the first data stream is completely full + virtual uint32_t GetLineNumber (void) = 0; // On output, zero is auto + virtual uint8_t GetDataStreamIndex (void) = 0; // Usually zero. Can only be 1 if non-SD and the first data stream is completely full protected: virtual ~IDeckLinkAncillaryPacket () {} // call Release method to drop reference count @@ -972,35 +989,33 @@ protected: class BMD_PUBLIC IDeckLinkAncillaryPacketIterator : public IUnknown { public: - virtual HRESULT Next (/* out */ IDeckLinkAncillaryPacket **packet) = 0; + virtual HRESULT Next (/* out */ IDeckLinkAncillaryPacket** packet) = 0; protected: virtual ~IDeckLinkAncillaryPacketIterator () {} // call Release method to drop reference count }; -/* Interface IDeckLinkVideoFrameAncillaryPackets - Obtained through QueryInterface() on an IDeckLinkVideoFrame object. */ +/* Interface IDeckLinkVideoFrameAncillaryPackets - Obtained through QueryInterface on an IDeckLinkVideoFrame object. */ class BMD_PUBLIC IDeckLinkVideoFrameAncillaryPackets : public IUnknown { public: - - virtual HRESULT GetPacketIterator (/* out */ IDeckLinkAncillaryPacketIterator **iterator) = 0; - virtual HRESULT GetFirstPacketByID (/* in */ uint8_t DID, /* in */ uint8_t SDID, /* out */ IDeckLinkAncillaryPacket **packet) = 0; - virtual HRESULT AttachPacket (/* in */ IDeckLinkAncillaryPacket *packet) = 0; // Implement IDeckLinkAncillaryPacket to output your own - virtual HRESULT DetachPacket (/* in */ IDeckLinkAncillaryPacket *packet) = 0; + virtual HRESULT GetPacketIterator (/* out */ IDeckLinkAncillaryPacketIterator** iterator) = 0; + virtual HRESULT GetFirstPacketByID (/* in */ uint8_t DID, /* in */ uint8_t SDID, /* out */ IDeckLinkAncillaryPacket** packet) = 0; + virtual HRESULT AttachPacket (/* in */ IDeckLinkAncillaryPacket* packet) = 0; // Implement IDeckLinkAncillaryPacket to output your own + virtual HRESULT DetachPacket (/* in */ IDeckLinkAncillaryPacket* packet) = 0; virtual HRESULT DetachAllPackets (void) = 0; protected: virtual ~IDeckLinkVideoFrameAncillaryPackets () {} // call Release method to drop reference count }; -/* Interface IDeckLinkVideoFrameAncillary - Use of IDeckLinkVideoFrameAncillaryPackets is preferred. Obtained through QueryInterface() on an IDeckLinkVideoFrame object. */ +/* Interface IDeckLinkVideoFrameAncillary - Use of IDeckLinkVideoFrameAncillaryPackets is preferred. Obtained through QueryInterface on an IDeckLinkVideoFrame object. */ class BMD_PUBLIC IDeckLinkVideoFrameAncillary : public IUnknown { public: - - virtual HRESULT GetBufferForVerticalBlankingLine (/* in */ uint32_t lineNumber, /* out */ void **buffer) = 0; // Pixels/rowbytes is same as display mode, except for above HD where it's 1920 pixels for UHD modes and 2048 pixels for DCI modes + virtual HRESULT GetBufferForVerticalBlankingLine (/* in */ uint32_t lineNumber, /* out */ void** buffer) = 0; // Pixels/rowbytes is same as display mode, except for above HD where it's 1920 pixels for UHD modes and 2048 pixels for DCI modes virtual BMDPixelFormat GetPixelFormat (void) = 0; virtual BMDDisplayMode GetDisplayMode (void) = 0; @@ -1013,9 +1028,9 @@ protected: class BMD_PUBLIC IDeckLinkEncoderPacket : public IUnknown { public: - virtual HRESULT GetBytes (/* out */ void **buffer) = 0; + virtual HRESULT GetBytes (/* out */ void** buffer) = 0; virtual long GetSize (void) = 0; - virtual HRESULT GetStreamTime (/* out */ BMDTimeValue *frameTime, /* in */ BMDTimeScale timeScale) = 0; + virtual HRESULT GetStreamTime (/* out */ BMDTimeValue* frameTime, /* in */ BMDTimeScale timeScale) = 0; virtual BMDPacketType GetPacketType (void) = 0; protected: @@ -1028,9 +1043,8 @@ class BMD_PUBLIC IDeckLinkEncoderVideoPacket : public IDeckLinkEncoderPacket { public: virtual BMDPixelFormat GetPixelFormat (void) = 0; - virtual HRESULT GetHardwareReferenceTimestamp (/* in */ BMDTimeScale timeScale, /* out */ BMDTimeValue *frameTime, /* out */ BMDTimeValue *frameDuration) = 0; - - virtual HRESULT GetTimecode (/* in */ BMDTimecodeFormat format, /* out */ IDeckLinkTimecode **timecode) = 0; + virtual HRESULT GetHardwareReferenceTimestamp (/* in */ BMDTimeScale timeScale, /* out */ BMDTimeValue* frameTime, /* out */ BMDTimeValue* frameDuration) = 0; + virtual HRESULT GetTimecode (/* in */ BMDTimecodeFormat format, /* out */ IDeckLinkTimecode** timecode) = 0; protected: virtual ~IDeckLinkEncoderVideoPacket () {} // call Release method to drop reference count @@ -1047,13 +1061,13 @@ protected: virtual ~IDeckLinkEncoderAudioPacket () {} // call Release method to drop reference count }; -/* Interface IDeckLinkH265NALPacket - Obtained through QueryInterface() on an IDeckLinkEncoderVideoPacket object */ +/* Interface IDeckLinkH265NALPacket - Obtained through QueryInterface on an IDeckLinkEncoderVideoPacket object */ class BMD_PUBLIC IDeckLinkH265NALPacket : public IDeckLinkEncoderVideoPacket { public: - virtual HRESULT GetUnitType (/* out */ uint8_t *unitType) = 0; - virtual HRESULT GetBytesNoPrefix (/* out */ void **buffer) = 0; + virtual HRESULT GetUnitType (/* out */ uint8_t* unitType) = 0; + virtual HRESULT GetBytesNoPrefix (/* out */ void** buffer) = 0; virtual long GetSizeNoPrefix (void) = 0; protected: @@ -1066,8 +1080,8 @@ class BMD_PUBLIC IDeckLinkAudioInputPacket : public IUnknown { public: virtual long GetSampleFrameCount (void) = 0; - virtual HRESULT GetBytes (/* out */ void **buffer) = 0; - virtual HRESULT GetPacketTime (/* out */ BMDTimeValue *packetTime, /* in */ BMDTimeScale timeScale) = 0; + virtual HRESULT GetBytes (/* out */ void** buffer) = 0; + virtual HRESULT GetPacketTime (/* out */ BMDTimeValue* packetTime, /* in */ BMDTimeScale timeScale) = 0; protected: virtual ~IDeckLinkAudioInputPacket () {} // call Release method to drop reference count @@ -1078,13 +1092,13 @@ protected: class BMD_PUBLIC IDeckLinkScreenPreviewCallback : public IUnknown { public: - virtual HRESULT DrawFrame (/* in */ IDeckLinkVideoFrame *theFrame) = 0; + virtual HRESULT DrawFrame (/* in */ IDeckLinkVideoFrame* theFrame) = 0; protected: virtual ~IDeckLinkScreenPreviewCallback () {} // call Release method to drop reference count }; -/* Interface IDeckLinkGLScreenPreviewHelper - Created with CoCreateInstance(). */ +/* Interface IDeckLinkGLScreenPreviewHelper - Created with CoCreateInstance on platforms with native COM support or from CreateOpenGLScreenPreviewHelper on other platforms. */ class BMD_PUBLIC IDeckLinkGLScreenPreviewHelper : public IUnknown { @@ -1094,7 +1108,7 @@ public: virtual HRESULT InitializeGL (void) = 0; virtual HRESULT PaintGL (void) = 0; - virtual HRESULT SetFrame (/* in */ IDeckLinkVideoFrame *theFrame) = 0; + virtual HRESULT SetFrame (/* in */ IDeckLinkVideoFrame* theFrame) = 0; virtual HRESULT Set3DPreviewFormat (/* in */ BMD3DPreviewFormat previewFormat) = 0; protected: @@ -1114,22 +1128,75 @@ public: class BMD_PUBLIC IDeckLinkNotification : public IUnknown { public: - virtual HRESULT Subscribe (/* in */ BMDNotifications topic, /* in */ IDeckLinkNotificationCallback *theCallback) = 0; - virtual HRESULT Unsubscribe (/* in */ BMDNotifications topic, /* in */ IDeckLinkNotificationCallback *theCallback) = 0; -}; - -/* Interface IDeckLinkAttributes - DeckLink Attribute interface */ - -class BMD_PUBLIC IDeckLinkAttributes : public IUnknown -{ -public: - virtual HRESULT GetFlag (/* in */ BMDDeckLinkAttributeID cfgID, /* out */ bool *value) = 0; - virtual HRESULT GetInt (/* in */ BMDDeckLinkAttributeID cfgID, /* out */ int64_t *value) = 0; - virtual HRESULT GetFloat (/* in */ BMDDeckLinkAttributeID cfgID, /* out */ double *value) = 0; - virtual HRESULT GetString (/* in */ BMDDeckLinkAttributeID cfgID, /* out */ const char **value) = 0; + virtual HRESULT Subscribe (/* in */ BMDNotifications topic, /* in */ IDeckLinkNotificationCallback* theCallback) = 0; + virtual HRESULT Unsubscribe (/* in */ BMDNotifications topic, /* in */ IDeckLinkNotificationCallback* theCallback) = 0; protected: - virtual ~IDeckLinkAttributes () {} // call Release method to drop reference count + virtual ~IDeckLinkNotification () {} // call Release method to drop reference count +}; + +/* Interface IDeckLinkProfileAttributes - Created by QueryInterface from an IDeckLinkProfile, or from IDeckLink. When queried from IDeckLink, interrogates the active profile */ + +class BMD_PUBLIC IDeckLinkProfileAttributes : public IUnknown +{ +public: + virtual HRESULT GetFlag (/* in */ BMDDeckLinkAttributeID cfgID, /* out */ bool* value) = 0; + virtual HRESULT GetInt (/* in */ BMDDeckLinkAttributeID cfgID, /* out */ int64_t* value) = 0; + virtual HRESULT GetFloat (/* in */ BMDDeckLinkAttributeID cfgID, /* out */ double* value) = 0; + virtual HRESULT GetString (/* in */ BMDDeckLinkAttributeID cfgID, /* out */ const char** value) = 0; + +protected: + virtual ~IDeckLinkProfileAttributes () {} // call Release method to drop reference count +}; + +/* Interface IDeckLinkProfileIterator - Enumerates IDeckLinkProfile interfaces */ + +class BMD_PUBLIC IDeckLinkProfileIterator : public IUnknown +{ +public: + virtual HRESULT Next (/* out */ IDeckLinkProfile** profile) = 0; + +protected: + virtual ~IDeckLinkProfileIterator () {} // call Release method to drop reference count +}; + +/* Interface IDeckLinkProfile - Represents the active profile when queried from IDeckLink */ + +class BMD_PUBLIC IDeckLinkProfile : public IUnknown +{ +public: + virtual HRESULT GetDevice (/* out */ IDeckLink** device) = 0; // Device affected when this profile becomes active + virtual HRESULT IsActive (/* out */ bool* isActive) = 0; + virtual HRESULT SetActive (void) = 0; // Activating a profile will also change the profile on all devices enumerated by GetPeers. Activation is not complete until IDeckLinkProfileCallback::ProfileActivated is called + virtual HRESULT GetPeers (/* out */ IDeckLinkProfileIterator** profileIterator) = 0; // Profiles of other devices activated with this profile + +protected: + virtual ~IDeckLinkProfile () {} // call Release method to drop reference count +}; + +/* Interface IDeckLinkProfileCallback - Receive notifications about profiles related to this device */ + +class BMD_PUBLIC IDeckLinkProfileCallback : public IUnknown +{ +public: + virtual HRESULT ProfileChanging (/* in */ IDeckLinkProfile* profileToBeActivated, /* in */ bool streamsWillBeForcedToStop) = 0; // Called before this device changes profile. User has an opportunity for teardown if streamsWillBeForcedToStop + virtual HRESULT ProfileActivated (/* in */ IDeckLinkProfile* activatedProfile) = 0; // Called after this device has been activated with a new profile + +protected: + virtual ~IDeckLinkProfileCallback () {} // call Release method to drop reference count +}; + +/* Interface IDeckLinkProfileManager - Created by QueryInterface from IDeckLink when a device has multiple optional profiles */ + +class BMD_PUBLIC IDeckLinkProfileManager : public IUnknown +{ +public: + virtual HRESULT GetProfiles (/* out */ IDeckLinkProfileIterator** profileIterator) = 0; // All available profiles for this device + virtual HRESULT GetProfile (/* in */ BMDProfileID profileID, /* out */ IDeckLinkProfile** profile) = 0; + virtual HRESULT SetCallback (/* in */ IDeckLinkProfileCallback* callback) = 0; + +protected: + virtual ~IDeckLinkProfileManager () {} // call Release method to drop reference count }; /* Interface IDeckLinkStatus - DeckLink Status interface */ @@ -1137,11 +1204,11 @@ protected: class BMD_PUBLIC IDeckLinkStatus : public IUnknown { public: - virtual HRESULT GetFlag (/* in */ BMDDeckLinkStatusID statusID, /* out */ bool *value) = 0; - virtual HRESULT GetInt (/* in */ BMDDeckLinkStatusID statusID, /* out */ int64_t *value) = 0; - virtual HRESULT GetFloat (/* in */ BMDDeckLinkStatusID statusID, /* out */ double *value) = 0; - virtual HRESULT GetString (/* in */ BMDDeckLinkStatusID statusID, /* out */ const char **value) = 0; - virtual HRESULT GetBytes (/* in */ BMDDeckLinkStatusID statusID, /* out */ void *buffer, /* in, out */ uint32_t *bufferSize) = 0; + virtual HRESULT GetFlag (/* in */ BMDDeckLinkStatusID statusID, /* out */ bool* value) = 0; + virtual HRESULT GetInt (/* in */ BMDDeckLinkStatusID statusID, /* out */ int64_t* value) = 0; + virtual HRESULT GetFloat (/* in */ BMDDeckLinkStatusID statusID, /* out */ double* value) = 0; + virtual HRESULT GetString (/* in */ BMDDeckLinkStatusID statusID, /* out */ const char** value) = 0; + virtual HRESULT GetBytes (/* in */ BMDDeckLinkStatusID statusID, /* out */ void* buffer, /* in, out */ uint32_t* bufferSize) = 0; protected: virtual ~IDeckLinkStatus () {} // call Release method to drop reference count @@ -1162,7 +1229,7 @@ protected: virtual ~IDeckLinkKeyer () {} // call Release method to drop reference count }; -/* Interface IDeckLinkVideoConversion - Created with CoCreateInstance(). */ +/* Interface IDeckLinkVideoConversion - Created with CoCreateInstance. */ class BMD_PUBLIC IDeckLinkVideoConversion : public IUnknown { @@ -1201,15 +1268,14 @@ protected: extern "C" { - IDeckLinkIterator* BMD_PUBLIC CreateDeckLinkIteratorInstance (void); - IDeckLinkDiscovery* BMD_PUBLIC CreateDeckLinkDiscoveryInstance (void); - IDeckLinkAPIInformation* BMD_PUBLIC CreateDeckLinkAPIInformationInstance (void); - IDeckLinkGLScreenPreviewHelper* BMD_PUBLIC CreateOpenGLScreenPreviewHelper (void); - IDeckLinkVideoConversion* BMD_PUBLIC CreateVideoConversionInstance (void); - IDeckLinkVideoFrameAncillaryPackets* BMD_PUBLIC CreateVideoFrameAncillaryPacketsInstance (void); // For use when creating a custom IDeckLinkVideoFrame without wrapping IDeckLinkOutput::CreateVideoFrame + IDeckLinkIterator* BMD_PUBLIC CreateDeckLinkIteratorInstance(void); + IDeckLinkDiscovery* BMD_PUBLIC CreateDeckLinkDiscoveryInstance(void); + IDeckLinkAPIInformation* BMD_PUBLIC CreateDeckLinkAPIInformationInstance(void); + IDeckLinkGLScreenPreviewHelper* BMD_PUBLIC CreateOpenGLScreenPreviewHelper(void); + IDeckLinkVideoConversion* BMD_PUBLIC CreateVideoConversionInstance(void); + IDeckLinkVideoFrameAncillaryPackets* BMD_PUBLIC CreateVideoFrameAncillaryPacketsInstance(void); // For use when creating a custom IDeckLinkVideoFrame without wrapping IDeckLinkOutput::CreateVideoFrame } - -#endif // defined(__cplusplus) +#endif /* defined(__cplusplus) */ #endif /* defined(BMD_DECKLINKAPI_H) */ diff --git a/plugins/decklink/linux/decklink-sdk/DeckLinkAPIConfiguration.h b/plugins/decklink/linux/decklink-sdk/DeckLinkAPIConfiguration.h index 430f871..bf1015b 100644 --- a/plugins/decklink/linux/decklink-sdk/DeckLinkAPIConfiguration.h +++ b/plugins/decklink/linux/decklink-sdk/DeckLinkAPIConfiguration.h @@ -1,5 +1,5 @@ /* -LICENSE-START- -** Copyright (c) 2018 Blackmagic Design +** Copyright (c) 2020 Blackmagic Design ** ** Permission is hereby granted, free of charge, to any person or organization ** obtaining a copy of the software and accompanying documentation covered by @@ -7,14 +7,14 @@ ** execute, and transmit the Software, and to prepare derivative works of the ** Software, and to permit third-parties to whom the Software is furnished to ** do so, all subject to the following: -** +** ** The copyright notices in the Software and this entire statement, including ** the above license grant, this restriction and the following disclaimer, ** must be included in all copies of the Software, in whole or in part, and ** all derivative works of the Software, unless such copies or derivative ** works are solely in the form of machine-executable object code generated by ** a source language processor. -** +** ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT @@ -46,8 +46,8 @@ // Interface ID Declarations -BMD_CONST REFIID IID_IDeckLinkConfiguration = /* EF90380B-4AE5-4346-9077-E288E149F129 */ {0xEF,0x90,0x38,0x0B,0x4A,0xE5,0x43,0x46,0x90,0x77,0xE2,0x88,0xE1,0x49,0xF1,0x29}; -BMD_CONST REFIID IID_IDeckLinkEncoderConfiguration = /* 138050E5-C60A-4552-BF3F-0F358049327E */ {0x13,0x80,0x50,0xE5,0xC6,0x0A,0x45,0x52,0xBF,0x3F,0x0F,0x35,0x80,0x49,0x32,0x7E}; +BMD_CONST REFIID IID_IDeckLinkConfiguration = /* 912F634B-2D4E-40A4-8AAB-8D80B73F1289 */ { 0x91,0x2F,0x63,0x4B,0x2D,0x4E,0x40,0xA4,0x8A,0xAB,0x8D,0x80,0xB7,0x3F,0x12,0x89 }; +BMD_CONST REFIID IID_IDeckLinkEncoderConfiguration = /* 138050E5-C60A-4552-BF3F-0F358049327E */ { 0x13,0x80,0x50,0xE5,0xC6,0x0A,0x45,0x52,0xBF,0x3F,0x0F,0x35,0x80,0x49,0x32,0x7E }; /* Enum BMDDeckLinkConfigurationID - DeckLink Configuration ID */ @@ -63,13 +63,14 @@ enum _BMDDeckLinkConfigurationID { bmdDeckLinkConfigHDMI3DPackingFormat = /* '3dpf' */ 0x33647066, bmdDeckLinkConfigBypass = /* 'byps' */ 0x62797073, bmdDeckLinkConfigClockTimingAdjustment = /* 'ctad' */ 0x63746164, - bmdDeckLinkConfigDuplexMode = /* 'dupx' */ 0x64757078, /* Audio Input/Output Flags */ bmdDeckLinkConfigAnalogAudioConsumerLevels = /* 'aacl' */ 0x6161636C, + bmdDeckLinkConfigSwapHDMICh3AndCh4OnInput = /* 'hi34' */ 0x68693334, + bmdDeckLinkConfigSwapHDMICh3AndCh4OnOutput = /* 'ho34' */ 0x686F3334, - /* Video output flags */ + /* Video Output Flags */ bmdDeckLinkConfigFieldFlickerRemoval = /* 'fdfr' */ 0x66646672, bmdDeckLinkConfigHD1080p24ToHD1080i5994Conversion = /* 'to59' */ 0x746F3539, @@ -80,9 +81,6 @@ enum _BMDDeckLinkConfigurationID { bmdDeckLinkConfigSMPTELevelAOutput = /* 'smta' */ 0x736D7461, bmdDeckLinkConfigRec2020Output = /* 'rec2' */ 0x72656332, // Ensure output is Rec.2020 colorspace bmdDeckLinkConfigQuadLinkSDIVideoOutputSquareDivisionSplit = /* 'SDQS' */ 0x53445153, - - /* Video Output Flags */ - bmdDeckLinkConfigOutput1080pAsPsF = /* 'pfpr' */ 0x70667072, /* Video Output Integers */ @@ -95,6 +93,8 @@ enum _BMDDeckLinkConfigurationID { bmdDeckLinkConfigDefaultVideoOutputMode = /* 'dvom' */ 0x64766F6D, bmdDeckLinkConfigDefaultVideoOutputModeFlags = /* 'dvof' */ 0x64766F66, bmdDeckLinkConfigSDIOutputLinkConfiguration = /* 'solc' */ 0x736F6C63, + bmdDeckLinkConfigHDMITimecodePacking = /* 'htpk' */ 0x6874706B, + bmdDeckLinkConfigPlaybackGroup = /* 'plgr' */ 0x706C6772, /* Video Output Floats */ @@ -111,9 +111,6 @@ enum _BMDDeckLinkConfigurationID { bmdDeckLinkConfigVideoInputScanning = /* 'visc' */ 0x76697363, // Applicable to H264 Pro Recorder only bmdDeckLinkConfigUseDedicatedLTCInput = /* 'dltc' */ 0x646C7463, // Use timecode from LTC input instead of SDI stream bmdDeckLinkConfigSDIInput3DPayloadOverride = /* '3dds' */ 0x33646473, - - /* Video Input Flags */ - bmdDeckLinkConfigCapture1080pAsPsF = /* 'cfpr' */ 0x63667072, /* Video Input Integers */ @@ -126,6 +123,7 @@ enum _BMDDeckLinkConfigurationID { bmdDeckLinkConfigVANCSourceLine2Mapping = /* 'vsl2' */ 0x76736C32, bmdDeckLinkConfigVANCSourceLine3Mapping = /* 'vsl3' */ 0x76736C33, bmdDeckLinkConfigCapturePassThroughMode = /* 'cptm' */ 0x6370746D, + bmdDeckLinkConfigCaptureGroup = /* 'cpgr' */ 0x63706772, /* Video Input Floats */ @@ -137,6 +135,10 @@ enum _BMDDeckLinkConfigurationID { bmdDeckLinkConfigVideoInputSVideoLumaGain = /* 'islg' */ 0x69736C67, bmdDeckLinkConfigVideoInputSVideoChromaGain = /* 'iscg' */ 0x69736367, + /* Keying Integers */ + + bmdDeckLinkConfigInternalKeyingAncillaryDataSource = /* 'ikas' */ 0x696B6173, + /* Audio Input Flags */ bmdDeckLinkConfigMicrophonePhantomPower = /* 'mphp' */ 0x6D706870, @@ -209,6 +211,8 @@ enum _BMDDeckLinkEncoderConfigurationID { bmdDeckLinkEncoderConfigMPEG4CodecSpecificDesc = /* 'esds' */ 0x65736473 // Sample description extensions only (atom stream, each with size and fourCC header). Useful for AVFoundation, VideoToolbox, MKV and more }; +#if defined(__cplusplus) + // Forward Declarations class IDeckLinkConfiguration; @@ -220,13 +224,13 @@ class BMD_PUBLIC IDeckLinkConfiguration : public IUnknown { public: virtual HRESULT SetFlag (/* in */ BMDDeckLinkConfigurationID cfgID, /* in */ bool value) = 0; - virtual HRESULT GetFlag (/* in */ BMDDeckLinkConfigurationID cfgID, /* out */ bool *value) = 0; + virtual HRESULT GetFlag (/* in */ BMDDeckLinkConfigurationID cfgID, /* out */ bool* value) = 0; virtual HRESULT SetInt (/* in */ BMDDeckLinkConfigurationID cfgID, /* in */ int64_t value) = 0; - virtual HRESULT GetInt (/* in */ BMDDeckLinkConfigurationID cfgID, /* out */ int64_t *value) = 0; + virtual HRESULT GetInt (/* in */ BMDDeckLinkConfigurationID cfgID, /* out */ int64_t* value) = 0; virtual HRESULT SetFloat (/* in */ BMDDeckLinkConfigurationID cfgID, /* in */ double value) = 0; - virtual HRESULT GetFloat (/* in */ BMDDeckLinkConfigurationID cfgID, /* out */ double *value) = 0; - virtual HRESULT SetString (/* in */ BMDDeckLinkConfigurationID cfgID, /* in */ const char *value) = 0; - virtual HRESULT GetString (/* in */ BMDDeckLinkConfigurationID cfgID, /* out */ const char **value) = 0; + virtual HRESULT GetFloat (/* in */ BMDDeckLinkConfigurationID cfgID, /* out */ double* value) = 0; + virtual HRESULT SetString (/* in */ BMDDeckLinkConfigurationID cfgID, /* in */ const char* value) = 0; + virtual HRESULT GetString (/* in */ BMDDeckLinkConfigurationID cfgID, /* out */ const char** value) = 0; virtual HRESULT WriteConfigurationToPreferences (void) = 0; protected: @@ -239,14 +243,14 @@ class BMD_PUBLIC IDeckLinkEncoderConfiguration : public IUnknown { public: virtual HRESULT SetFlag (/* in */ BMDDeckLinkEncoderConfigurationID cfgID, /* in */ bool value) = 0; - virtual HRESULT GetFlag (/* in */ BMDDeckLinkEncoderConfigurationID cfgID, /* out */ bool *value) = 0; + virtual HRESULT GetFlag (/* in */ BMDDeckLinkEncoderConfigurationID cfgID, /* out */ bool* value) = 0; virtual HRESULT SetInt (/* in */ BMDDeckLinkEncoderConfigurationID cfgID, /* in */ int64_t value) = 0; - virtual HRESULT GetInt (/* in */ BMDDeckLinkEncoderConfigurationID cfgID, /* out */ int64_t *value) = 0; + virtual HRESULT GetInt (/* in */ BMDDeckLinkEncoderConfigurationID cfgID, /* out */ int64_t* value) = 0; virtual HRESULT SetFloat (/* in */ BMDDeckLinkEncoderConfigurationID cfgID, /* in */ double value) = 0; - virtual HRESULT GetFloat (/* in */ BMDDeckLinkEncoderConfigurationID cfgID, /* out */ double *value) = 0; - virtual HRESULT SetString (/* in */ BMDDeckLinkEncoderConfigurationID cfgID, /* in */ const char *value) = 0; - virtual HRESULT GetString (/* in */ BMDDeckLinkEncoderConfigurationID cfgID, /* out */ const char **value) = 0; - virtual HRESULT GetBytes (/* in */ BMDDeckLinkEncoderConfigurationID cfgID, /* out */ void *buffer /* optional */, /* in, out */ uint32_t *bufferSize) = 0; + virtual HRESULT GetFloat (/* in */ BMDDeckLinkEncoderConfigurationID cfgID, /* out */ double* value) = 0; + virtual HRESULT SetString (/* in */ BMDDeckLinkEncoderConfigurationID cfgID, /* in */ const char* value) = 0; + virtual HRESULT GetString (/* in */ BMDDeckLinkEncoderConfigurationID cfgID, /* out */ const char** value) = 0; + virtual HRESULT GetBytes (/* in */ BMDDeckLinkEncoderConfigurationID cfgID, /* out */ void* buffer /* optional */, /* in, out */ uint32_t* bufferSize) = 0; protected: virtual ~IDeckLinkEncoderConfiguration () {} // call Release method to drop reference count @@ -259,5 +263,5 @@ extern "C" { } - +#endif /* defined(__cplusplus) */ #endif /* defined(BMD_DECKLINKAPICONFIGURATION_H) */ diff --git a/plugins/decklink/linux/decklink-sdk/DeckLinkAPIConfiguration_v10_11.h b/plugins/decklink/linux/decklink-sdk/DeckLinkAPIConfiguration_v10_11.h new file mode 100644 index 0000000..e715b20 --- /dev/null +++ b/plugins/decklink/linux/decklink-sdk/DeckLinkAPIConfiguration_v10_11.h @@ -0,0 +1,71 @@ +/* -LICENSE-START- +** Copyright (c) 2017 Blackmagic Design +** +** Permission is hereby granted, free of charge, to any person or organization +** obtaining a copy of the software and accompanying documentation covered by +** this license (the "Software") to use, reproduce, display, distribute, +** execute, and transmit the Software, and to prepare derivative works of the +** Software, and to permit third-parties to whom the Software is furnished to +** do so, all subject to the following: +** +** The copyright notices in the Software and this entire statement, including +** the above license grant, this restriction and the following disclaimer, +** must be included in all copies of the Software, in whole or in part, and +** all derivative works of the Software, unless such copies or derivative +** works are solely in the form of machine-executable object code generated by +** a source language processor. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +** SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +** FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +** DEALINGS IN THE SOFTWARE. +** -LICENSE-END- +*/ + +#ifndef BMD_DECKLINKAPICONFIGURATION_v10_11_H +#define BMD_DECKLINKAPICONFIGURATION_v10_11_H + +#include "DeckLinkAPIConfiguration.h" + +// Interface ID Declarations + +BMD_CONST REFIID IID_IDeckLinkConfiguration_v10_11 = /* EF90380B-4AE5-4346-9077-E288E149F129 */ {0xEF,0x90,0x38,0x0B,0x4A,0xE5,0x43,0x46,0x90,0x77,0xE2,0x88,0xE1,0x49,0xF1,0x29}; + +/* Enum BMDDeckLinkConfigurationID_v10_11 - DeckLink Configuration ID */ + +typedef uint32_t BMDDeckLinkConfigurationID_v10_11; +enum _BMDDeckLinkConfigurationID_v10_11 { + + /* Video Input/Output Integers */ + + bmdDeckLinkConfigDuplexMode_v10_11 = /* 'dupx' */ 0x64757078, +}; + +// Forward Declarations + +class IDeckLinkConfiguration_v10_11; + +/* Interface IDeckLinkConfiguration_v10_11 - DeckLink Configuration interface */ + +class BMD_PUBLIC IDeckLinkConfiguration_v10_11 : public IUnknown +{ +public: + virtual HRESULT SetFlag (/* in */ BMDDeckLinkConfigurationID cfgID, /* in */ bool value) = 0; + virtual HRESULT GetFlag (/* in */ BMDDeckLinkConfigurationID cfgID, /* out */ bool *value) = 0; + virtual HRESULT SetInt (/* in */ BMDDeckLinkConfigurationID cfgID, /* in */ int64_t value) = 0; + virtual HRESULT GetInt (/* in */ BMDDeckLinkConfigurationID cfgID, /* out */ int64_t *value) = 0; + virtual HRESULT SetFloat (/* in */ BMDDeckLinkConfigurationID cfgID, /* in */ double value) = 0; + virtual HRESULT GetFloat (/* in */ BMDDeckLinkConfigurationID cfgID, /* out */ double *value) = 0; + virtual HRESULT SetString (/* in */ BMDDeckLinkConfigurationID cfgID, /* in */ const char *value) = 0; + virtual HRESULT GetString (/* in */ BMDDeckLinkConfigurationID cfgID, /* out */ const char **value) = 0; + virtual HRESULT WriteConfigurationToPreferences (void) = 0; + +protected: + virtual ~IDeckLinkConfiguration_v10_11 () {} // call Release method to drop reference count +}; + + +#endif /* defined(BMD_DECKLINKAPICONFIGURATION_v10_11_H) */ diff --git a/plugins/decklink/linux/decklink-sdk/DeckLinkAPIDeckControl.h b/plugins/decklink/linux/decklink-sdk/DeckLinkAPIDeckControl.h index e0522a2..79e90f9 100644 --- a/plugins/decklink/linux/decklink-sdk/DeckLinkAPIDeckControl.h +++ b/plugins/decklink/linux/decklink-sdk/DeckLinkAPIDeckControl.h @@ -1,5 +1,5 @@ /* -LICENSE-START- -** Copyright (c) 2018 Blackmagic Design +** Copyright (c) 2020 Blackmagic Design ** ** Permission is hereby granted, free of charge, to any person or organization ** obtaining a copy of the software and accompanying documentation covered by @@ -7,14 +7,14 @@ ** execute, and transmit the Software, and to prepare derivative works of the ** Software, and to permit third-parties to whom the Software is furnished to ** do so, all subject to the following: -** +** ** The copyright notices in the Software and this entire statement, including ** the above license grant, this restriction and the following disclaimer, ** must be included in all copies of the Software, in whole or in part, and ** all derivative works of the Software, unless such copies or derivative ** works are solely in the form of machine-executable object code generated by ** a source language processor. -** +** ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT @@ -46,8 +46,8 @@ // Interface ID Declarations -BMD_CONST REFIID IID_IDeckLinkDeckControlStatusCallback = /* 53436FFB-B434-4906-BADC-AE3060FFE8EF */ {0x53,0x43,0x6F,0xFB,0xB4,0x34,0x49,0x06,0xBA,0xDC,0xAE,0x30,0x60,0xFF,0xE8,0xEF}; -BMD_CONST REFIID IID_IDeckLinkDeckControl = /* 8E1C3ACE-19C7-4E00-8B92-D80431D958BE */ {0x8E,0x1C,0x3A,0xCE,0x19,0xC7,0x4E,0x00,0x8B,0x92,0xD8,0x04,0x31,0xD9,0x58,0xBE}; +BMD_CONST REFIID IID_IDeckLinkDeckControlStatusCallback = /* 53436FFB-B434-4906-BADC-AE3060FFE8EF */ { 0x53,0x43,0x6F,0xFB,0xB4,0x34,0x49,0x06,0xBA,0xDC,0xAE,0x30,0x60,0xFF,0xE8,0xEF }; +BMD_CONST REFIID IID_IDeckLinkDeckControl = /* 8E1C3ACE-19C7-4E00-8B92-D80431D958BE */ { 0x8E,0x1C,0x3A,0xCE,0x19,0xC7,0x4E,0x00,0x8B,0x92,0xD8,0x04,0x31,0xD9,0x58,0xBE }; /* Enum BMDDeckControlMode - DeckControl mode */ @@ -67,13 +67,13 @@ enum _BMDDeckControlEvent { /* Export-To-Tape events */ - bmdDeckControlPrepareForExportEvent = /* 'pfee' */ 0x70666565, // This event is triggered a few frames before reaching the in-point. IDeckLinkInput::StartScheduledPlayback() should be called at this point. - bmdDeckControlExportCompleteEvent = /* 'exce' */ 0x65786365, // This event is triggered a few frames after reaching the out-point. At this point, it is safe to stop playback. + bmdDeckControlPrepareForExportEvent = /* 'pfee' */ 0x70666565, // This event is triggered a few frames before reaching the in-point. IDeckLinkInput::StartScheduledPlayback should be called at this point. + bmdDeckControlExportCompleteEvent = /* 'exce' */ 0x65786365, // This event is triggered a few frames after reaching the out-point. At this point, it is safe to stop playback. Upon reception of this event the deck's control mode is set back to bmdDeckControlVTRControlMode. /* Capture events */ bmdDeckControlPrepareForCaptureEvent = /* 'pfce' */ 0x70666365, // This event is triggered a few frames before reaching the in-point. The serial timecode attached to IDeckLinkVideoInputFrames is now valid. - bmdDeckControlCaptureCompleteEvent = /* 'ccev' */ 0x63636576 // This event is triggered a few frames after reaching the out-point. + bmdDeckControlCaptureCompleteEvent = /* 'ccev' */ 0x63636576 // This event is triggered a few frames after reaching the out-point. Upon reception of this event the deck's control mode is set back to bmdDeckControlVTRControlMode. }; /* Enum BMDDeckControlVTRControlState - VTR Control state */ @@ -146,6 +146,8 @@ enum _BMDDeckControlError { bmdDeckControlUnknownError = /* 'uner' */ 0x756E6572 }; +#if defined(__cplusplus) + // Forward Declarations class IDeckLinkDeckControlStatusCallback; @@ -170,39 +172,39 @@ protected: class BMD_PUBLIC IDeckLinkDeckControl : public IUnknown { public: - virtual HRESULT Open (/* in */ BMDTimeScale timeScale, /* in */ BMDTimeValue timeValue, /* in */ bool timecodeIsDropFrame, /* out */ BMDDeckControlError *error) = 0; + virtual HRESULT Open (/* in */ BMDTimeScale timeScale, /* in */ BMDTimeValue timeValue, /* in */ bool timecodeIsDropFrame, /* out */ BMDDeckControlError* error) = 0; virtual HRESULT Close (/* in */ bool standbyOn) = 0; - virtual HRESULT GetCurrentState (/* out */ BMDDeckControlMode *mode, /* out */ BMDDeckControlVTRControlState *vtrControlState, /* out */ BMDDeckControlStatusFlags *flags) = 0; + virtual HRESULT GetCurrentState (/* out */ BMDDeckControlMode* mode, /* out */ BMDDeckControlVTRControlState* vtrControlState, /* out */ BMDDeckControlStatusFlags* flags) = 0; virtual HRESULT SetStandby (/* in */ bool standbyOn) = 0; - virtual HRESULT SendCommand (/* in */ uint8_t *inBuffer, /* in */ uint32_t inBufferSize, /* out */ uint8_t *outBuffer, /* out */ uint32_t *outDataSize, /* in */ uint32_t outBufferSize, /* out */ BMDDeckControlError *error) = 0; - virtual HRESULT Play (/* out */ BMDDeckControlError *error) = 0; - virtual HRESULT Stop (/* out */ BMDDeckControlError *error) = 0; - virtual HRESULT TogglePlayStop (/* out */ BMDDeckControlError *error) = 0; - virtual HRESULT Eject (/* out */ BMDDeckControlError *error) = 0; - virtual HRESULT GoToTimecode (/* in */ BMDTimecodeBCD timecode, /* out */ BMDDeckControlError *error) = 0; - virtual HRESULT FastForward (/* in */ bool viewTape, /* out */ BMDDeckControlError *error) = 0; - virtual HRESULT Rewind (/* in */ bool viewTape, /* out */ BMDDeckControlError *error) = 0; - virtual HRESULT StepForward (/* out */ BMDDeckControlError *error) = 0; - virtual HRESULT StepBack (/* out */ BMDDeckControlError *error) = 0; - virtual HRESULT Jog (/* in */ double rate, /* out */ BMDDeckControlError *error) = 0; - virtual HRESULT Shuttle (/* in */ double rate, /* out */ BMDDeckControlError *error) = 0; - virtual HRESULT GetTimecodeString (/* out */ const char **currentTimeCode, /* out */ BMDDeckControlError *error) = 0; - virtual HRESULT GetTimecode (/* out */ IDeckLinkTimecode **currentTimecode, /* out */ BMDDeckControlError *error) = 0; - virtual HRESULT GetTimecodeBCD (/* out */ BMDTimecodeBCD *currentTimecode, /* out */ BMDDeckControlError *error) = 0; + virtual HRESULT SendCommand (/* in */ uint8_t* inBuffer, /* in */ uint32_t inBufferSize, /* out */ uint8_t* outBuffer, /* out */ uint32_t* outDataSize, /* in */ uint32_t outBufferSize, /* out */ BMDDeckControlError* error) = 0; + virtual HRESULT Play (/* out */ BMDDeckControlError* error) = 0; + virtual HRESULT Stop (/* out */ BMDDeckControlError* error) = 0; + virtual HRESULT TogglePlayStop (/* out */ BMDDeckControlError* error) = 0; + virtual HRESULT Eject (/* out */ BMDDeckControlError* error) = 0; + virtual HRESULT GoToTimecode (/* in */ BMDTimecodeBCD timecode, /* out */ BMDDeckControlError* error) = 0; + virtual HRESULT FastForward (/* in */ bool viewTape, /* out */ BMDDeckControlError* error) = 0; + virtual HRESULT Rewind (/* in */ bool viewTape, /* out */ BMDDeckControlError* error) = 0; + virtual HRESULT StepForward (/* out */ BMDDeckControlError* error) = 0; + virtual HRESULT StepBack (/* out */ BMDDeckControlError* error) = 0; + virtual HRESULT Jog (/* in */ double rate, /* out */ BMDDeckControlError* error) = 0; + virtual HRESULT Shuttle (/* in */ double rate, /* out */ BMDDeckControlError* error) = 0; + virtual HRESULT GetTimecodeString (/* out */ const char** currentTimeCode, /* out */ BMDDeckControlError* error) = 0; + virtual HRESULT GetTimecode (/* out */ IDeckLinkTimecode** currentTimecode, /* out */ BMDDeckControlError* error) = 0; + virtual HRESULT GetTimecodeBCD (/* out */ BMDTimecodeBCD* currentTimecode, /* out */ BMDDeckControlError* error) = 0; virtual HRESULT SetPreroll (/* in */ uint32_t prerollSeconds) = 0; - virtual HRESULT GetPreroll (/* out */ uint32_t *prerollSeconds) = 0; + virtual HRESULT GetPreroll (/* out */ uint32_t* prerollSeconds) = 0; virtual HRESULT SetExportOffset (/* in */ int32_t exportOffsetFields) = 0; - virtual HRESULT GetExportOffset (/* out */ int32_t *exportOffsetFields) = 0; - virtual HRESULT GetManualExportOffset (/* out */ int32_t *deckManualExportOffsetFields) = 0; + virtual HRESULT GetExportOffset (/* out */ int32_t* exportOffsetFields) = 0; + virtual HRESULT GetManualExportOffset (/* out */ int32_t* deckManualExportOffsetFields) = 0; virtual HRESULT SetCaptureOffset (/* in */ int32_t captureOffsetFields) = 0; - virtual HRESULT GetCaptureOffset (/* out */ int32_t *captureOffsetFields) = 0; - virtual HRESULT StartExport (/* in */ BMDTimecodeBCD inTimecode, /* in */ BMDTimecodeBCD outTimecode, /* in */ BMDDeckControlExportModeOpsFlags exportModeOps, /* out */ BMDDeckControlError *error) = 0; - virtual HRESULT StartCapture (/* in */ bool useVITC, /* in */ BMDTimecodeBCD inTimecode, /* in */ BMDTimecodeBCD outTimecode, /* out */ BMDDeckControlError *error) = 0; - virtual HRESULT GetDeviceID (/* out */ uint16_t *deviceId, /* out */ BMDDeckControlError *error) = 0; + virtual HRESULT GetCaptureOffset (/* out */ int32_t* captureOffsetFields) = 0; + virtual HRESULT StartExport (/* in */ BMDTimecodeBCD inTimecode, /* in */ BMDTimecodeBCD outTimecode, /* in */ BMDDeckControlExportModeOpsFlags exportModeOps, /* out */ BMDDeckControlError* error) = 0; + virtual HRESULT StartCapture (/* in */ bool useVITC, /* in */ BMDTimecodeBCD inTimecode, /* in */ BMDTimecodeBCD outTimecode, /* out */ BMDDeckControlError* error) = 0; + virtual HRESULT GetDeviceID (/* out */ uint16_t* deviceId, /* out */ BMDDeckControlError* error) = 0; virtual HRESULT Abort (void) = 0; - virtual HRESULT CrashRecordStart (/* out */ BMDDeckControlError *error) = 0; - virtual HRESULT CrashRecordStop (/* out */ BMDDeckControlError *error) = 0; - virtual HRESULT SetCallback (/* in */ IDeckLinkDeckControlStatusCallback *callback) = 0; + virtual HRESULT CrashRecordStart (/* out */ BMDDeckControlError* error) = 0; + virtual HRESULT CrashRecordStop (/* out */ BMDDeckControlError* error) = 0; + virtual HRESULT SetCallback (/* in */ IDeckLinkDeckControlStatusCallback* callback) = 0; protected: virtual ~IDeckLinkDeckControl () {} // call Release method to drop reference count @@ -215,5 +217,5 @@ extern "C" { } - +#endif /* defined(__cplusplus) */ #endif /* defined(BMD_DECKLINKAPIDECKCONTROL_H) */ diff --git a/plugins/decklink/linux/decklink-sdk/DeckLinkAPIDiscovery.h b/plugins/decklink/linux/decklink-sdk/DeckLinkAPIDiscovery.h index d6619ca..e8f1a7b 100644 --- a/plugins/decklink/linux/decklink-sdk/DeckLinkAPIDiscovery.h +++ b/plugins/decklink/linux/decklink-sdk/DeckLinkAPIDiscovery.h @@ -1,5 +1,5 @@ /* -LICENSE-START- -** Copyright (c) 2018 Blackmagic Design +** Copyright (c) 2020 Blackmagic Design ** ** Permission is hereby granted, free of charge, to any person or organization ** obtaining a copy of the software and accompanying documentation covered by @@ -7,14 +7,14 @@ ** execute, and transmit the Software, and to prepare derivative works of the ** Software, and to permit third-parties to whom the Software is furnished to ** do so, all subject to the following: -** +** ** The copyright notices in the Software and this entire statement, including ** the above license grant, this restriction and the following disclaimer, ** must be included in all copies of the Software, in whole or in part, and ** all derivative works of the Software, unless such copies or derivative ** works are solely in the form of machine-executable object code generated by ** a source language processor. -** +** ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT @@ -46,19 +46,21 @@ // Interface ID Declarations -BMD_CONST REFIID IID_IDeckLink = /* C418FBDD-0587-48ED-8FE5-640F0A14AF91 */ {0xC4,0x18,0xFB,0xDD,0x05,0x87,0x48,0xED,0x8F,0xE5,0x64,0x0F,0x0A,0x14,0xAF,0x91}; +BMD_CONST REFIID IID_IDeckLink = /* C418FBDD-0587-48ED-8FE5-640F0A14AF91 */ { 0xC4,0x18,0xFB,0xDD,0x05,0x87,0x48,0xED,0x8F,0xE5,0x64,0x0F,0x0A,0x14,0xAF,0x91 }; + +#if defined(__cplusplus) // Forward Declarations class IDeckLink; -/* Interface IDeckLink - represents a DeckLink device */ +/* Interface IDeckLink - Represents a DeckLink device */ class BMD_PUBLIC IDeckLink : public IUnknown { public: - virtual HRESULT GetModelName (/* out */ const char **modelName) = 0; - virtual HRESULT GetDisplayName (/* out */ const char **displayName) = 0; + virtual HRESULT GetModelName (/* out */ const char** modelName) = 0; + virtual HRESULT GetDisplayName (/* out */ const char** displayName) = 0; protected: virtual ~IDeckLink () {} // call Release method to drop reference count @@ -71,5 +73,5 @@ extern "C" { } - +#endif /* defined(__cplusplus) */ #endif /* defined(BMD_DECKLINKAPIDISCOVERY_H) */ diff --git a/plugins/decklink/linux/decklink-sdk/DeckLinkAPIDispatch.cpp b/plugins/decklink/linux/decklink-sdk/DeckLinkAPIDispatch.cpp index 880cf34..faef470 100644 --- a/plugins/decklink/linux/decklink-sdk/DeckLinkAPIDispatch.cpp +++ b/plugins/decklink/linux/decklink-sdk/DeckLinkAPIDispatch.cpp @@ -66,7 +66,7 @@ static void InitDeckLinkAPI (void) gLoadedDeckLinkAPI = true; - gCreateIteratorFunc = (CreateIteratorFunc)dlsym(libraryHandle, "CreateDeckLinkIteratorInstance_0003"); + gCreateIteratorFunc = (CreateIteratorFunc)dlsym(libraryHandle, "CreateDeckLinkIteratorInstance_0004"); if (!gCreateIteratorFunc) fprintf(stderr, "%s\n", dlerror()); gCreateAPIInformationFunc = (CreateAPIInformationFunc)dlsym(libraryHandle, "CreateDeckLinkAPIInformationInstance_0001"); @@ -75,7 +75,7 @@ static void InitDeckLinkAPI (void) gCreateVideoConversionFunc = (CreateVideoConversionInstanceFunc)dlsym(libraryHandle, "CreateVideoConversionInstance_0001"); if (!gCreateVideoConversionFunc) fprintf(stderr, "%s\n", dlerror()); - gCreateDeckLinkDiscoveryFunc = (CreateDeckLinkDiscoveryInstanceFunc)dlsym(libraryHandle, "CreateDeckLinkDiscoveryInstance_0002"); + gCreateDeckLinkDiscoveryFunc = (CreateDeckLinkDiscoveryInstanceFunc)dlsym(libraryHandle, "CreateDeckLinkDiscoveryInstance_0003"); if (!gCreateDeckLinkDiscoveryFunc) fprintf(stderr, "%s\n", dlerror()); gCreateVideoFrameAncillaryPacketsFunc = (CreateVideoFrameAncillaryPacketsInstanceFunc)dlsym(libraryHandle, "CreateVideoFrameAncillaryPacketsInstance_0001"); diff --git a/plugins/decklink/linux/decklink-sdk/DeckLinkAPIDispatch_v10_11.cpp b/plugins/decklink/linux/decklink-sdk/DeckLinkAPIDispatch_v10_11.cpp new file mode 100644 index 0000000..219aaa1 --- /dev/null +++ b/plugins/decklink/linux/decklink-sdk/DeckLinkAPIDispatch_v10_11.cpp @@ -0,0 +1,160 @@ +/* -LICENSE-START- +** Copyright (c) 2019 Blackmagic Design +** +** Permission is hereby granted, free of charge, to any person or organization +** obtaining a copy of the software and accompanying documentation covered by +** this license (the "Software") to use, reproduce, display, distribute, +** execute, and transmit the Software, and to prepare derivative works of the +** Software, and to permit third-parties to whom the Software is furnished to +** do so, all subject to the following: +** +** The copyright notices in the Software and this entire statement, including +** the above license grant, this restriction and the following disclaimer, +** must be included in all copies of the Software, in whole or in part, and +** all derivative works of the Software, unless such copies or derivative +** works are solely in the form of machine-executable object code generated by +** a source language processor. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +** SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +** FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +** DEALINGS IN THE SOFTWARE. +** -LICENSE-END- +**/ + +#include +#include +#include + +#include "DeckLinkAPI_v10_11.h" + +#define kDeckLinkAPI_Name "libDeckLinkAPI.so" +#define KDeckLinkPreviewAPI_Name "libDeckLinkPreviewAPI.so" + +typedef IDeckLinkIterator* (*CreateIteratorFunc)(void); +typedef IDeckLinkAPIInformation* (*CreateAPIInformationFunc)(void); +typedef IDeckLinkGLScreenPreviewHelper* (*CreateOpenGLScreenPreviewHelperFunc)(void); +typedef IDeckLinkVideoConversion* (*CreateVideoConversionInstanceFunc)(void); +typedef IDeckLinkDiscovery* (*CreateDeckLinkDiscoveryInstanceFunc)(void); +typedef IDeckLinkVideoFrameAncillaryPackets* (*CreateVideoFrameAncillaryPacketsInstanceFunc)(void); + +static pthread_once_t gDeckLinkOnceControl = PTHREAD_ONCE_INIT; +static pthread_once_t gPreviewOnceControl = PTHREAD_ONCE_INIT; + +static bool gLoadedDeckLinkAPI = false; + +static CreateIteratorFunc gCreateIteratorFunc = NULL; +static CreateAPIInformationFunc gCreateAPIInformationFunc = NULL; +static CreateOpenGLScreenPreviewHelperFunc gCreateOpenGLPreviewFunc = NULL; +static CreateVideoConversionInstanceFunc gCreateVideoConversionFunc = NULL; +static CreateDeckLinkDiscoveryInstanceFunc gCreateDeckLinkDiscoveryFunc = NULL; +static CreateVideoFrameAncillaryPacketsInstanceFunc gCreateVideoFrameAncillaryPacketsFunc = NULL; + +static void InitDeckLinkAPI (void) +{ + void *libraryHandle; + + libraryHandle = dlopen(kDeckLinkAPI_Name, RTLD_NOW|RTLD_GLOBAL); + if (!libraryHandle) + { + fprintf(stderr, "%s\n", dlerror()); + return; + } + + gLoadedDeckLinkAPI = true; + + gCreateIteratorFunc = (CreateIteratorFunc)dlsym(libraryHandle, "CreateDeckLinkIteratorInstance_0003"); + if (!gCreateIteratorFunc) + fprintf(stderr, "%s\n", dlerror()); + gCreateAPIInformationFunc = (CreateAPIInformationFunc)dlsym(libraryHandle, "CreateDeckLinkAPIInformationInstance_0001"); + if (!gCreateAPIInformationFunc) + fprintf(stderr, "%s\n", dlerror()); + gCreateVideoConversionFunc = (CreateVideoConversionInstanceFunc)dlsym(libraryHandle, "CreateVideoConversionInstance_0001"); + if (!gCreateVideoConversionFunc) + fprintf(stderr, "%s\n", dlerror()); + gCreateDeckLinkDiscoveryFunc = (CreateDeckLinkDiscoveryInstanceFunc)dlsym(libraryHandle, "CreateDeckLinkDiscoveryInstance_0002"); + if (!gCreateDeckLinkDiscoveryFunc) + fprintf(stderr, "%s\n", dlerror()); + gCreateVideoFrameAncillaryPacketsFunc = (CreateVideoFrameAncillaryPacketsInstanceFunc)dlsym(libraryHandle, "CreateVideoFrameAncillaryPacketsInstance_0001"); + if (!gCreateVideoFrameAncillaryPacketsFunc) + fprintf(stderr, "%s\n", dlerror()); +} + +static void InitDeckLinkPreviewAPI (void) +{ + void *libraryHandle; + + libraryHandle = dlopen(KDeckLinkPreviewAPI_Name, RTLD_NOW|RTLD_GLOBAL); + if (!libraryHandle) + { + fprintf(stderr, "%s\n", dlerror()); + return; + } + gCreateOpenGLPreviewFunc = (CreateOpenGLScreenPreviewHelperFunc)dlsym(libraryHandle, "CreateOpenGLScreenPreviewHelper_0001"); + if (!gCreateOpenGLPreviewFunc) + fprintf(stderr, "%s\n", dlerror()); +} + +bool IsDeckLinkAPIPresent_v10_11 (void) +{ + // If the DeckLink API dynamic library was successfully loaded, return this knowledge to the caller + return gLoadedDeckLinkAPI; +} + +IDeckLinkIterator* CreateDeckLinkIteratorInstance_v10_11 (void) +{ + pthread_once(&gDeckLinkOnceControl, InitDeckLinkAPI); + + if (gCreateIteratorFunc == NULL) + return NULL; + return gCreateIteratorFunc(); +} + +IDeckLinkAPIInformation* CreateDeckLinkAPIInformationInstance_v10_11 (void) +{ + pthread_once(&gDeckLinkOnceControl, InitDeckLinkAPI); + + if (gCreateAPIInformationFunc == NULL) + return NULL; + return gCreateAPIInformationFunc(); +} + +IDeckLinkGLScreenPreviewHelper* CreateOpenGLScreenPreviewHelper_v10_11 (void) +{ + pthread_once(&gDeckLinkOnceControl, InitDeckLinkAPI); + pthread_once(&gPreviewOnceControl, InitDeckLinkPreviewAPI); + + if (gCreateOpenGLPreviewFunc == NULL) + return NULL; + return gCreateOpenGLPreviewFunc(); +} + +IDeckLinkVideoConversion* CreateVideoConversionInstance_v10_11 (void) +{ + pthread_once(&gDeckLinkOnceControl, InitDeckLinkAPI); + + if (gCreateVideoConversionFunc == NULL) + return NULL; + return gCreateVideoConversionFunc(); +} + +IDeckLinkDiscovery* CreateDeckLinkDiscoveryInstance_v10_11 (void) +{ + pthread_once(&gDeckLinkOnceControl, InitDeckLinkAPI); + + if (gCreateDeckLinkDiscoveryFunc == NULL) + return NULL; + return gCreateDeckLinkDiscoveryFunc(); +} + +IDeckLinkVideoFrameAncillaryPackets* CreateVideoFrameAncillaryPacketsInstance_v10_11 (void) +{ + pthread_once(&gDeckLinkOnceControl, InitDeckLinkAPI); + + if (gCreateVideoFrameAncillaryPacketsFunc == NULL) + return NULL; + return gCreateVideoFrameAncillaryPacketsFunc(); +} diff --git a/plugins/decklink/linux/decklink-sdk/DeckLinkAPIModes.h b/plugins/decklink/linux/decklink-sdk/DeckLinkAPIModes.h index 543aaa1..a7d14ee 100644 --- a/plugins/decklink/linux/decklink-sdk/DeckLinkAPIModes.h +++ b/plugins/decklink/linux/decklink-sdk/DeckLinkAPIModes.h @@ -1,5 +1,5 @@ /* -LICENSE-START- -** Copyright (c) 2018 Blackmagic Design +** Copyright (c) 2020 Blackmagic Design ** ** Permission is hereby granted, free of charge, to any person or organization ** obtaining a copy of the software and accompanying documentation covered by @@ -7,14 +7,14 @@ ** execute, and transmit the Software, and to prepare derivative works of the ** Software, and to permit third-parties to whom the Software is furnished to ** do so, all subject to the following: -** +** ** The copyright notices in the Software and this entire statement, including ** the above license grant, this restriction and the following disclaimer, ** must be included in all copies of the Software, in whole or in part, and ** all derivative works of the Software, unless such copies or derivative ** works are solely in the form of machine-executable object code generated by ** a source language processor. -** +** ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT @@ -46,10 +46,10 @@ // Interface ID Declarations -BMD_CONST REFIID IID_IDeckLinkDisplayModeIterator = /* 9C88499F-F601-4021-B80B-032E4EB41C35 */ {0x9C,0x88,0x49,0x9F,0xF6,0x01,0x40,0x21,0xB8,0x0B,0x03,0x2E,0x4E,0xB4,0x1C,0x35}; -BMD_CONST REFIID IID_IDeckLinkDisplayMode = /* 3EB2C1AB-0A3D-4523-A3AD-F40D7FB14E78 */ {0x3E,0xB2,0xC1,0xAB,0x0A,0x3D,0x45,0x23,0xA3,0xAD,0xF4,0x0D,0x7F,0xB1,0x4E,0x78}; +BMD_CONST REFIID IID_IDeckLinkDisplayModeIterator = /* 9C88499F-F601-4021-B80B-032E4EB41C35 */ { 0x9C,0x88,0x49,0x9F,0xF6,0x01,0x40,0x21,0xB8,0x0B,0x03,0x2E,0x4E,0xB4,0x1C,0x35 }; +BMD_CONST REFIID IID_IDeckLinkDisplayMode = /* 3EB2C1AB-0A3D-4523-A3AD-F40D7FB14E78 */ { 0x3E,0xB2,0xC1,0xAB,0x0A,0x3D,0x45,0x23,0xA3,0xAD,0xF4,0x0D,0x7F,0xB1,0x4E,0x78 }; -/* Enum BMDDisplayMode - Video display modes */ +/* Enum BMDDisplayMode - BMDDisplayMode enumerates the video modes supported. */ typedef uint32_t BMDDisplayMode; enum _BMDDisplayMode { @@ -69,9 +69,16 @@ enum _BMDDisplayMode { bmdModeHD1080p25 = /* 'Hp25' */ 0x48703235, bmdModeHD1080p2997 = /* 'Hp29' */ 0x48703239, bmdModeHD1080p30 = /* 'Hp30' */ 0x48703330, + bmdModeHD1080p4795 = /* 'Hp47' */ 0x48703437, + bmdModeHD1080p48 = /* 'Hp48' */ 0x48703438, bmdModeHD1080p50 = /* 'Hp50' */ 0x48703530, bmdModeHD1080p5994 = /* 'Hp59' */ 0x48703539, bmdModeHD1080p6000 = /* 'Hp60' */ 0x48703630, // N.B. This _really_ is 60.00 Hz. + bmdModeHD1080p9590 = /* 'Hp95' */ 0x48703935, + bmdModeHD1080p96 = /* 'Hp96' */ 0x48703936, + bmdModeHD1080p100 = /* 'Hp10' */ 0x48703130, + bmdModeHD1080p11988 = /* 'Hp11' */ 0x48703131, + bmdModeHD1080p120 = /* 'Hp12' */ 0x48703132, bmdModeHD1080i50 = /* 'Hi50' */ 0x48693530, bmdModeHD1080i5994 = /* 'Hi59' */ 0x48693539, bmdModeHD1080i6000 = /* 'Hi60' */ 0x48693630, // N.B. This _really_ is 60.00 Hz. @@ -95,9 +102,16 @@ enum _BMDDisplayMode { bmdMode2kDCI25 = /* '2d25' */ 0x32643235, bmdMode2kDCI2997 = /* '2d29' */ 0x32643239, bmdMode2kDCI30 = /* '2d30' */ 0x32643330, + bmdMode2kDCI4795 = /* '2d47' */ 0x32643437, + bmdMode2kDCI48 = /* '2d48' */ 0x32643438, bmdMode2kDCI50 = /* '2d50' */ 0x32643530, bmdMode2kDCI5994 = /* '2d59' */ 0x32643539, bmdMode2kDCI60 = /* '2d60' */ 0x32643630, + bmdMode2kDCI9590 = /* '2d95' */ 0x32643935, + bmdMode2kDCI96 = /* '2d96' */ 0x32643936, + bmdMode2kDCI100 = /* '2d10' */ 0x32643130, + bmdMode2kDCI11988 = /* '2d11' */ 0x32643131, + bmdMode2kDCI120 = /* '2d12' */ 0x32643132, /* 4K UHD Modes */ @@ -106,9 +120,16 @@ enum _BMDDisplayMode { bmdMode4K2160p25 = /* '4k25' */ 0x346B3235, bmdMode4K2160p2997 = /* '4k29' */ 0x346B3239, bmdMode4K2160p30 = /* '4k30' */ 0x346B3330, + bmdMode4K2160p4795 = /* '4k47' */ 0x346B3437, + bmdMode4K2160p48 = /* '4k48' */ 0x346B3438, bmdMode4K2160p50 = /* '4k50' */ 0x346B3530, bmdMode4K2160p5994 = /* '4k59' */ 0x346B3539, bmdMode4K2160p60 = /* '4k60' */ 0x346B3630, + bmdMode4K2160p9590 = /* '4k95' */ 0x346B3935, + bmdMode4K2160p96 = /* '4k96' */ 0x346B3936, + bmdMode4K2160p100 = /* '4k10' */ 0x346B3130, + bmdMode4K2160p11988 = /* '4k11' */ 0x346B3131, + bmdMode4K2160p120 = /* '4k12' */ 0x346B3132, /* 4K DCI Modes */ @@ -117,9 +138,16 @@ enum _BMDDisplayMode { bmdMode4kDCI25 = /* '4d25' */ 0x34643235, bmdMode4kDCI2997 = /* '4d29' */ 0x34643239, bmdMode4kDCI30 = /* '4d30' */ 0x34643330, + bmdMode4kDCI4795 = /* '4d47' */ 0x34643437, + bmdMode4kDCI48 = /* '4d48' */ 0x34643438, bmdMode4kDCI50 = /* '4d50' */ 0x34643530, bmdMode4kDCI5994 = /* '4d59' */ 0x34643539, bmdMode4kDCI60 = /* '4d60' */ 0x34643630, + bmdMode4kDCI9590 = /* '4d95' */ 0x34643935, + bmdMode4kDCI96 = /* '4d96' */ 0x34643936, + bmdMode4kDCI100 = /* '4d10' */ 0x34643130, + bmdMode4kDCI11988 = /* '4d11' */ 0x34643131, + bmdMode4kDCI120 = /* '4d12' */ 0x34643132, /* 8K UHD Modes */ @@ -128,6 +156,8 @@ enum _BMDDisplayMode { bmdMode8K4320p25 = /* '8k25' */ 0x386B3235, bmdMode8K4320p2997 = /* '8k29' */ 0x386B3239, bmdMode8K4320p30 = /* '8k30' */ 0x386B3330, + bmdMode8K4320p4795 = /* '8k47' */ 0x386B3437, + bmdMode8K4320p48 = /* '8k48' */ 0x386B3438, bmdMode8K4320p50 = /* '8k50' */ 0x386B3530, bmdMode8K4320p5994 = /* '8k59' */ 0x386B3539, bmdMode8K4320p60 = /* '8k60' */ 0x386B3630, @@ -139,21 +169,37 @@ enum _BMDDisplayMode { bmdMode8kDCI25 = /* '8d25' */ 0x38643235, bmdMode8kDCI2997 = /* '8d29' */ 0x38643239, bmdMode8kDCI30 = /* '8d30' */ 0x38643330, + bmdMode8kDCI4795 = /* '8d47' */ 0x38643437, + bmdMode8kDCI48 = /* '8d48' */ 0x38643438, bmdMode8kDCI50 = /* '8d50' */ 0x38643530, bmdMode8kDCI5994 = /* '8d59' */ 0x38643539, bmdMode8kDCI60 = /* '8d60' */ 0x38643630, - /* RAW Modes for Cintel (input only) */ + /* PC Modes */ - bmdModeCintelRAW = /* 'rwci' */ 0x72776369, // Frame size up to 4096x3072, variable frame rate - bmdModeCintelCompressedRAW = /* 'rwcc' */ 0x72776363, // Frame size up to 4096x3072, variable frame rate + bmdMode640x480p60 = /* 'vga6' */ 0x76676136, + bmdMode800x600p60 = /* 'svg6' */ 0x73766736, + bmdMode1440x900p50 = /* 'wxg5' */ 0x77786735, + bmdMode1440x900p60 = /* 'wxg6' */ 0x77786736, + bmdMode1440x1080p50 = /* 'sxg5' */ 0x73786735, + bmdMode1440x1080p60 = /* 'sxg6' */ 0x73786736, + bmdMode1600x1200p50 = /* 'uxg5' */ 0x75786735, + bmdMode1600x1200p60 = /* 'uxg6' */ 0x75786736, + bmdMode1920x1200p50 = /* 'wux5' */ 0x77757835, + bmdMode1920x1200p60 = /* 'wux6' */ 0x77757836, + bmdMode1920x1440p50 = /* '1945' */ 0x31393435, + bmdMode1920x1440p60 = /* '1946' */ 0x31393436, + bmdMode2560x1440p50 = /* 'wqh5' */ 0x77716835, + bmdMode2560x1440p60 = /* 'wqh6' */ 0x77716836, + bmdMode2560x1600p50 = /* 'wqx5' */ 0x77717835, + bmdMode2560x1600p60 = /* 'wqx6' */ 0x77717836, /* Special Modes */ bmdModeUnknown = /* 'iunk' */ 0x69756E6B }; -/* Enum BMDFieldDominance - Video field dominance */ +/* Enum BMDFieldDominance - BMDFieldDominance enumerates settings applicable to video fields. */ typedef uint32_t BMDFieldDominance; enum _BMDFieldDominance { @@ -168,6 +214,7 @@ enum _BMDFieldDominance { typedef uint32_t BMDPixelFormat; enum _BMDPixelFormat { + bmdFormatUnspecified = 0, bmdFormat8BitYUV = /* '2vuy' */ 0x32767579, bmdFormat10BitYUV = /* 'v210' */ 0x76323130, bmdFormat8BitARGB = 32, @@ -181,12 +228,7 @@ enum _BMDPixelFormat { /* AVID DNxHR */ - bmdFormatDNxHR = /* 'AVdh' */ 0x41566468, - - /* Cintel formats */ - - bmdFormat12BitRAWGRBG = /* 'r12p' */ 0x72313270, // 12-bit RAW data for bayer pattern GRBG - bmdFormat12BitRAWJPEG = /* 'r16p' */ 0x72313670 // 12-bit RAW data arranged in tiles and JPEG compressed + bmdFormatDNxHR = /* 'AVdh' */ 0x41566468 }; /* Enum BMDDisplayModeFlags - Flags to describe the characteristics of an IDeckLinkDisplayMode. */ @@ -199,32 +241,34 @@ enum _BMDDisplayModeFlags { bmdDisplayModeColorspaceRec2020 = 1 << 3 }; +#if defined(__cplusplus) + // Forward Declarations class IDeckLinkDisplayModeIterator; class IDeckLinkDisplayMode; -/* Interface IDeckLinkDisplayModeIterator - enumerates over supported input/output display modes. */ +/* Interface IDeckLinkDisplayModeIterator - Enumerates over supported input/output display modes. */ class BMD_PUBLIC IDeckLinkDisplayModeIterator : public IUnknown { public: - virtual HRESULT Next (/* out */ IDeckLinkDisplayMode **deckLinkDisplayMode) = 0; + virtual HRESULT Next (/* out */ IDeckLinkDisplayMode** deckLinkDisplayMode) = 0; protected: virtual ~IDeckLinkDisplayModeIterator () {} // call Release method to drop reference count }; -/* Interface IDeckLinkDisplayMode - represents a display mode */ +/* Interface IDeckLinkDisplayMode - Represents a display mode */ class BMD_PUBLIC IDeckLinkDisplayMode : public IUnknown { public: - virtual HRESULT GetName (/* out */ const char **name) = 0; + virtual HRESULT GetName (/* out */ const char** name) = 0; virtual BMDDisplayMode GetDisplayMode (void) = 0; virtual long GetWidth (void) = 0; virtual long GetHeight (void) = 0; - virtual HRESULT GetFrameRate (/* out */ BMDTimeValue *frameDuration, /* out */ BMDTimeScale *timeScale) = 0; + virtual HRESULT GetFrameRate (/* out */ BMDTimeValue* frameDuration, /* out */ BMDTimeScale* timeScale) = 0; virtual BMDFieldDominance GetFieldDominance (void) = 0; virtual BMDDisplayModeFlags GetFlags (void) = 0; @@ -239,5 +283,5 @@ extern "C" { } - +#endif /* defined(__cplusplus) */ #endif /* defined(BMD_DECKLINKAPIMODES_H) */ diff --git a/plugins/decklink/linux/decklink-sdk/DeckLinkAPITypes.h b/plugins/decklink/linux/decklink-sdk/DeckLinkAPITypes.h index 5591262..1dbab74 100644 --- a/plugins/decklink/linux/decklink-sdk/DeckLinkAPITypes.h +++ b/plugins/decklink/linux/decklink-sdk/DeckLinkAPITypes.h @@ -1,5 +1,5 @@ /* -LICENSE-START- -** Copyright (c) 2018 Blackmagic Design +** Copyright (c) 2020 Blackmagic Design ** ** Permission is hereby granted, free of charge, to any person or organization ** obtaining a copy of the software and accompanying documentation covered by @@ -7,14 +7,14 @@ ** execute, and transmit the Software, and to prepare derivative works of the ** Software, and to permit third-parties to whom the Software is furnished to ** do so, all subject to the following: -** +** ** The copyright notices in the Software and this entire statement, including ** the above license grant, this restriction and the following disclaimer, ** must be included in all copies of the Software, in whole or in part, and ** all derivative works of the Software, unless such copies or derivative ** works are solely in the form of machine-executable object code generated by ** a source language processor. -** +** ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT @@ -50,7 +50,7 @@ typedef uint32_t BMDTimecodeUserBits; // Interface ID Declarations -BMD_CONST REFIID IID_IDeckLinkTimecode = /* BC6CFBD3-8317-4325-AC1C-1216391E9340 */ {0xBC,0x6C,0xFB,0xD3,0x83,0x17,0x43,0x25,0xAC,0x1C,0x12,0x16,0x39,0x1E,0x93,0x40}; +BMD_CONST REFIID IID_IDeckLinkTimecode = /* BC6CFBD3-8317-4325-AC1C-1216391E9340 */ { 0xBC,0x6C,0xFB,0xD3,0x83,0x17,0x43,0x25,0xAC,0x1C,0x12,0x16,0x39,0x1E,0x93,0x40 }; /* Enum BMDTimecodeFlags - Timecode flags */ @@ -59,13 +59,16 @@ enum _BMDTimecodeFlags { bmdTimecodeFlagDefault = 0, bmdTimecodeIsDropFrame = 1 << 0, bmdTimecodeFieldMark = 1 << 1, - bmdTimecodeColorFrame = 1 << 2 + bmdTimecodeColorFrame = 1 << 2, + bmdTimecodeEmbedRecordingTrigger = 1 << 3, // On SDI recording trigger utilises a user-bit. + bmdTimecodeRecordingTriggered = 1 << 4 }; /* Enum BMDVideoConnection - Video connection types */ typedef uint32_t BMDVideoConnection; enum _BMDVideoConnection { + bmdVideoConnectionUnspecified = 0, bmdVideoConnectionSDI = 1 << 0, bmdVideoConnectionHDMI = 1 << 1, bmdVideoConnectionOpticalSDI = 1 << 2, @@ -95,6 +98,8 @@ enum _BMDDeckControlConnection { bmdDeckControlConnectionRS422Remote2 = 1 << 1 }; +#if defined(__cplusplus) + // Forward Declarations class IDeckLinkTimecode; @@ -105,10 +110,10 @@ class BMD_PUBLIC IDeckLinkTimecode : public IUnknown { public: virtual BMDTimecodeBCD GetBCD (void) = 0; - virtual HRESULT GetComponents (/* out */ uint8_t *hours, /* out */ uint8_t *minutes, /* out */ uint8_t *seconds, /* out */ uint8_t *frames) = 0; - virtual HRESULT GetString (/* out */ const char **timecode) = 0; + virtual HRESULT GetComponents (/* out */ uint8_t* hours, /* out */ uint8_t* minutes, /* out */ uint8_t* seconds, /* out */ uint8_t* frames) = 0; + virtual HRESULT GetString (/* out */ const char** timecode) = 0; virtual BMDTimecodeFlags GetFlags (void) = 0; - virtual HRESULT GetTimecodeUserBits (/* out */ BMDTimecodeUserBits *userBits) = 0; + virtual HRESULT GetTimecodeUserBits (/* out */ BMDTimecodeUserBits* userBits) = 0; protected: virtual ~IDeckLinkTimecode () {} // call Release method to drop reference count @@ -121,5 +126,5 @@ extern "C" { } - +#endif /* defined(__cplusplus) */ #endif /* defined(BMD_DECKLINKAPITYPES_H) */ diff --git a/plugins/decklink/linux/decklink-sdk/DeckLinkAPIVersion.h b/plugins/decklink/linux/decklink-sdk/DeckLinkAPIVersion.h index f9db7ff..dcdeeb1 100644 --- a/plugins/decklink/linux/decklink-sdk/DeckLinkAPIVersion.h +++ b/plugins/decklink/linux/decklink-sdk/DeckLinkAPIVersion.h @@ -30,8 +30,8 @@ #ifndef __DeckLink_API_Version_h__ #define __DeckLink_API_Version_h__ -#define BLACKMAGIC_DECKLINK_API_VERSION 0x0a0b0400 -#define BLACKMAGIC_DECKLINK_API_VERSION_STRING "10.11.4" +#define BLACKMAGIC_DECKLINK_API_VERSION 0x0b060000 +#define BLACKMAGIC_DECKLINK_API_VERSION_STRING "11.6" #endif // __DeckLink_API_Version_h__ diff --git a/plugins/decklink/linux/decklink-sdk/DeckLinkAPIVideoEncoderInput_v10_11.h b/plugins/decklink/linux/decklink-sdk/DeckLinkAPIVideoEncoderInput_v10_11.h new file mode 100644 index 0000000..0ddd8bb --- /dev/null +++ b/plugins/decklink/linux/decklink-sdk/DeckLinkAPIVideoEncoderInput_v10_11.h @@ -0,0 +1,74 @@ +/* -LICENSE-START- +** Copyright (c) 2017 Blackmagic Design +** +** Permission is hereby granted, free of charge, to any person or organization +** obtaining a copy of the software and accompanying documentation covered by +** this license (the "Software") to use, reproduce, display, distribute, +** execute, and transmit the Software, and to prepare derivative works of the +** Software, and to permit third-parties to whom the Software is furnished to +** do so, all subject to the following: +** +** The copyright notices in the Software and this entire statement, including +** the above license grant, this restriction and the following disclaimer, +** must be included in all copies of the Software, in whole or in part, and +** all derivative works of the Software, unless such copies or derivative +** works are solely in the form of machine-executable object code generated by +** a source language processor. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +** SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +** FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +** DEALINGS IN THE SOFTWARE. +** -LICENSE-END- +*/ + +#ifndef BMD_DECKLINKAPIVIDEOENCODERINPUT_v10_11_H +#define BMD_DECKLINKAPIVIDEOENCODERINPUT_v10_11_H + +#include "DeckLinkAPI.h" +#include "DeckLinkAPI_v10_11.h" + +// Type Declarations +BMD_CONST REFIID IID_IDeckLinkEncoderInput_v10_11 = /* 270587DA-6B7D-42E7-A1F0-6D853F581185 */ {0x27,0x05,0x87,0xDA,0x6B,0x7D,0x42,0xE7,0xA1,0xF0,0x6D,0x85,0x3F,0x58,0x11,0x85}; + +/* Interface IDeckLinkEncoderInput_v10_11 - Created by QueryInterface from IDeckLink. */ + +class IDeckLinkEncoderInput_v10_11 : public IUnknown +{ +public: + virtual HRESULT DoesSupportVideoMode (/* in */ BMDDisplayMode displayMode, /* in */ BMDPixelFormat pixelFormat, /* in */ BMDVideoInputFlags flags, /* out */ BMDDisplayModeSupport_v10_11 *result, /* out */ IDeckLinkDisplayMode **resultDisplayMode) = 0; + virtual HRESULT GetDisplayModeIterator (/* out */ IDeckLinkDisplayModeIterator **iterator) = 0; + + /* Video Input */ + + virtual HRESULT EnableVideoInput (/* in */ BMDDisplayMode displayMode, /* in */ BMDPixelFormat pixelFormat, /* in */ BMDVideoInputFlags flags) = 0; + virtual HRESULT DisableVideoInput (void) = 0; + virtual HRESULT GetAvailablePacketsCount (/* out */ uint32_t *availablePacketsCount) = 0; + virtual HRESULT SetMemoryAllocator (/* in */ IDeckLinkMemoryAllocator *theAllocator) = 0; + + /* Audio Input */ + + virtual HRESULT EnableAudioInput (/* in */ BMDAudioFormat audioFormat, /* in */ BMDAudioSampleRate sampleRate, /* in */ BMDAudioSampleType sampleType, /* in */ uint32_t channelCount) = 0; + virtual HRESULT DisableAudioInput (void) = 0; + virtual HRESULT GetAvailableAudioSampleFrameCount (/* out */ uint32_t *availableSampleFrameCount) = 0; + + /* Input Control */ + + virtual HRESULT StartStreams (void) = 0; + virtual HRESULT StopStreams (void) = 0; + virtual HRESULT PauseStreams (void) = 0; + virtual HRESULT FlushStreams (void) = 0; + virtual HRESULT SetCallback (/* in */ IDeckLinkEncoderInputCallback *theCallback) = 0; + + /* Hardware Timing */ + + virtual HRESULT GetHardwareReferenceClock (/* in */ BMDTimeScale desiredTimeScale, /* out */ BMDTimeValue *hardwareTime, /* out */ BMDTimeValue *timeInFrame, /* out */ BMDTimeValue *ticksPerFrame) = 0; + +protected: + virtual ~IDeckLinkEncoderInput_v10_11 () {} // call Release method to drop reference count +}; + +#endif /* defined(BMD_DECKLINKAPIVIDEOENCODERINPUT_v10_11_H) */ diff --git a/plugins/decklink/linux/decklink-sdk/DeckLinkAPIVideoInput_v10_11.h b/plugins/decklink/linux/decklink-sdk/DeckLinkAPIVideoInput_v10_11.h new file mode 100644 index 0000000..a1e4753 --- /dev/null +++ b/plugins/decklink/linux/decklink-sdk/DeckLinkAPIVideoInput_v10_11.h @@ -0,0 +1,76 @@ +/* -LICENSE-START- +** Copyright (c) 2017 Blackmagic Design +** +** Permission is hereby granted, free of charge, to any person or organization +** obtaining a copy of the software and accompanying documentation covered by +** this license (the "Software") to use, reproduce, display, distribute, +** execute, and transmit the Software, and to prepare derivative works of the +** Software, and to permit third-parties to whom the Software is furnished to +** do so, all subject to the following: +** +** The copyright notices in the Software and this entire statement, including +** the above license grant, this restriction and the following disclaimer, +** must be included in all copies of the Software, in whole or in part, and +** all derivative works of the Software, unless such copies or derivative +** works are solely in the form of machine-executable object code generated by +** a source language processor. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +** SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +** FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +** DEALINGS IN THE SOFTWARE. +** -LICENSE-END- +*/ + +#ifndef BMD_DECKLINKAPIVIDEOINPUT_v10_11_H +#define BMD_DECKLINKAPIVIDEOINPUT_v10_11_H + +#include "DeckLinkAPI.h" +#include "DeckLinkAPI_v10_11.h" + +// Type Declarations +BMD_CONST REFIID IID_IDeckLinkInput_v10_11 = /* AF22762B-DFAC-4846-AA79-FA8883560995 */ {0xAF,0x22,0x76,0x2B,0xDF,0xAC,0x48,0x46,0xAA,0x79,0xFA,0x88,0x83,0x56,0x09,0x95}; + +/* Interface IDeckLinkInput_v10_11 - DeckLink input interface. */ + +class IDeckLinkInput_v10_11 : public IUnknown +{ +public: + virtual HRESULT DoesSupportVideoMode (/* in */ BMDDisplayMode displayMode, /* in */ BMDPixelFormat pixelFormat, /* in */ BMDVideoInputFlags flags, /* out */ BMDDisplayModeSupport_v10_11 *result, /* out */ IDeckLinkDisplayMode **resultDisplayMode) = 0; + virtual HRESULT GetDisplayModeIterator (/* out */ IDeckLinkDisplayModeIterator **iterator) = 0; + + virtual HRESULT SetScreenPreviewCallback (/* in */ IDeckLinkScreenPreviewCallback *previewCallback) = 0; + + /* Video Input */ + + virtual HRESULT EnableVideoInput (/* in */ BMDDisplayMode displayMode, /* in */ BMDPixelFormat pixelFormat, /* in */ BMDVideoInputFlags flags) = 0; + virtual HRESULT DisableVideoInput (void) = 0; + virtual HRESULT GetAvailableVideoFrameCount (/* out */ uint32_t *availableFrameCount) = 0; + virtual HRESULT SetVideoInputFrameMemoryAllocator (/* in */ IDeckLinkMemoryAllocator *theAllocator) = 0; + + /* Audio Input */ + + virtual HRESULT EnableAudioInput (/* in */ BMDAudioSampleRate sampleRate, /* in */ BMDAudioSampleType sampleType, /* in */ uint32_t channelCount) = 0; + virtual HRESULT DisableAudioInput (void) = 0; + virtual HRESULT GetAvailableAudioSampleFrameCount (/* out */ uint32_t *availableSampleFrameCount) = 0; + + /* Input Control */ + + virtual HRESULT StartStreams (void) = 0; + virtual HRESULT StopStreams (void) = 0; + virtual HRESULT PauseStreams (void) = 0; + virtual HRESULT FlushStreams (void) = 0; + virtual HRESULT SetCallback (/* in */ IDeckLinkInputCallback *theCallback) = 0; + + /* Hardware Timing */ + + virtual HRESULT GetHardwareReferenceClock (/* in */ BMDTimeScale desiredTimeScale, /* out */ BMDTimeValue *hardwareTime, /* out */ BMDTimeValue *timeInFrame, /* out */ BMDTimeValue *ticksPerFrame) = 0; + +protected: + virtual ~IDeckLinkInput_v10_11 () {} // call Release method to drop reference count +}; + +#endif /* defined(BMD_DECKLINKAPIVIDEOINPUT_v10_11_H) */ diff --git a/plugins/decklink/linux/decklink-sdk/DeckLinkAPIVideoInput_v11_4.h b/plugins/decklink/linux/decklink-sdk/DeckLinkAPIVideoInput_v11_4.h new file mode 100644 index 0000000..daa61bd --- /dev/null +++ b/plugins/decklink/linux/decklink-sdk/DeckLinkAPIVideoInput_v11_4.h @@ -0,0 +1,75 @@ +/* -LICENSE-START- +** Copyright (c) 2019 Blackmagic Design +** +** Permission is hereby granted, free of charge, to any person or organization +** obtaining a copy of the software and accompanying documentation covered by +** this license (the "Software") to use, reproduce, display, distribute, +** execute, and transmit the Software, and to prepare derivative works of the +** Software, and to permit third-parties to whom the Software is furnished to +** do so, all subject to the following: +** +** The copyright notices in the Software and this entire statement, including +** the above license grant, this restriction and the following disclaimer, +** must be included in all copies of the Software, in whole or in part, and +** all derivative works of the Software, unless such copies or derivative +** works are solely in the form of machine-executable object code generated by +** a source language processor. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +** SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +** FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +** DEALINGS IN THE SOFTWARE. +** -LICENSE-END- +*/ + +#ifndef BMD_DECKLINKAPIVIDEOINPUT_v11_4_H +#define BMD_DECKLINKAPIVIDEOINPUT_v11_4_H + +#include "DeckLinkAPI.h" + +// Type Declarations +BMD_CONST REFIID IID_IDeckLinkInput_v11_4 = /* 2A88CF76-F494-4216-A7EF-DC74EEB83882 */ { 0x2A,0x88,0xCF,0x76,0xF4,0x94,0x42,0x16,0xA7,0xEF,0xDC,0x74,0xEE,0xB8,0x38,0x82 }; + +/* Interface IDeckLinkInput - Created by QueryInterface from IDeckLink. */ + +class BMD_PUBLIC IDeckLinkInput_v11_4 : public IUnknown +{ +public: + virtual HRESULT DoesSupportVideoMode (/* in */ BMDVideoConnection connection /* If a value of 0 is specified, the caller does not care about the connection */, /* in */ BMDDisplayMode requestedMode, /* in */ BMDPixelFormat requestedPixelFormat, /* in */ BMDSupportedVideoModeFlags flags, /* out */ bool* supported) = 0; + virtual HRESULT GetDisplayMode (/* in */ BMDDisplayMode displayMode, /* out */ IDeckLinkDisplayMode** resultDisplayMode) = 0; + virtual HRESULT GetDisplayModeIterator (/* out */ IDeckLinkDisplayModeIterator** iterator) = 0; + virtual HRESULT SetScreenPreviewCallback (/* in */ IDeckLinkScreenPreviewCallback* previewCallback) = 0; + + /* Video Input */ + + virtual HRESULT EnableVideoInput (/* in */ BMDDisplayMode displayMode, /* in */ BMDPixelFormat pixelFormat, /* in */ BMDVideoInputFlags flags) = 0; + virtual HRESULT DisableVideoInput (void) = 0; + virtual HRESULT GetAvailableVideoFrameCount (/* out */ uint32_t* availableFrameCount) = 0; + virtual HRESULT SetVideoInputFrameMemoryAllocator (/* in */ IDeckLinkMemoryAllocator* theAllocator) = 0; + + /* Audio Input */ + + virtual HRESULT EnableAudioInput (/* in */ BMDAudioSampleRate sampleRate, /* in */ BMDAudioSampleType sampleType, /* in */ uint32_t channelCount) = 0; + virtual HRESULT DisableAudioInput (void) = 0; + virtual HRESULT GetAvailableAudioSampleFrameCount (/* out */ uint32_t* availableSampleFrameCount) = 0; + + /* Input Control */ + + virtual HRESULT StartStreams (void) = 0; + virtual HRESULT StopStreams (void) = 0; + virtual HRESULT PauseStreams (void) = 0; + virtual HRESULT FlushStreams (void) = 0; + virtual HRESULT SetCallback (/* in */ IDeckLinkInputCallback* theCallback) = 0; + + /* Hardware Timing */ + + virtual HRESULT GetHardwareReferenceClock (/* in */ BMDTimeScale desiredTimeScale, /* out */ BMDTimeValue* hardwareTime, /* out */ BMDTimeValue* timeInFrame, /* out */ BMDTimeValue* ticksPerFrame) = 0; + +protected: + virtual ~IDeckLinkInput_v11_4 () {} // call Release method to drop reference count +}; + +#endif /* defined(BMD_DECKLINKAPIVIDEOINPUT_v11_4_H) */ diff --git a/plugins/decklink/linux/decklink-sdk/DeckLinkAPIVideoInput_v11_5_1.h b/plugins/decklink/linux/decklink-sdk/DeckLinkAPIVideoInput_v11_5_1.h new file mode 100644 index 0000000..cd031bd --- /dev/null +++ b/plugins/decklink/linux/decklink-sdk/DeckLinkAPIVideoInput_v11_5_1.h @@ -0,0 +1,89 @@ +/* -LICENSE-START- +** Copyright (c) 2020 Blackmagic Design +** +** Permission is hereby granted, free of charge, to any person or organization +** obtaining a copy of the software and accompanying documentation covered by +** this license (the "Software") to use, reproduce, display, distribute, +** execute, and transmit the Software, and to prepare derivative works of the +** Software, and to permit third-parties to whom the Software is furnished to +** do so, all subject to the following: +** +** The copyright notices in the Software and this entire statement, including +** the above license grant, this restriction and the following disclaimer, +** must be included in all copies of the Software, in whole or in part, and +** all derivative works of the Software, unless such copies or derivative +** works are solely in the form of machine-executable object code generated by +** a source language processor. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +** SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +** FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +** DEALINGS IN THE SOFTWARE. +** -LICENSE-END- +*/ + +#ifndef BMD_DECKLINKAPIVIDEOINPUT_v11_5_1_H +#define BMD_DECKLINKAPIVIDEOINPUT_v11_5_1_H + +#include "DeckLinkAPI.h" + +// Type Declarations + +BMD_CONST REFIID IID_IDeckLinkInputCallback_v11_5_1 = /* DD04E5EC-7415-42AB-AE4A-E80C4DFC044A */ { 0xDD, 0x04, 0xE5, 0xEC, 0x74, 0x15, 0x42, 0xAB, 0xAE, 0x4A, 0xE8, 0x0C, 0x4D, 0xFC, 0x04, 0x4A }; +BMD_CONST REFIID IID_IDeckLinkInput_v11_5_1 = /* 9434C6E4-B15D-4B1C-979E-661E3DDCB4B9 */ { 0x94, 0x34, 0xC6, 0xE4, 0xB1, 0x5D, 0x4B, 0x1C, 0x97, 0x9E, 0x66, 0x1E, 0x3D, 0xDC, 0xB4, 0xB9 }; + +/* Interface IDeckLinkInputCallback_v11_5_1 - Frame arrival callback. */ + +class BMD_PUBLIC IDeckLinkInputCallback_v11_5_1 : public IUnknown +{ +public: + virtual HRESULT VideoInputFormatChanged (/* in */ BMDVideoInputFormatChangedEvents notificationEvents, /* in */ IDeckLinkDisplayMode* newDisplayMode, /* in */ BMDDetectedVideoInputFormatFlags detectedSignalFlags) = 0; + virtual HRESULT VideoInputFrameArrived (/* in */ IDeckLinkVideoInputFrame* videoFrame, /* in */ IDeckLinkAudioInputPacket* audioPacket) = 0; + +protected: + virtual ~IDeckLinkInputCallback_v11_5_1 () {} // call Release method to drop reference count +}; + +/* Interface IDeckLinkInput_v11_5_1 - Created by QueryInterface from IDeckLink. */ + +class BMD_PUBLIC IDeckLinkInput_v11_5_1 : public IUnknown +{ +public: + virtual HRESULT DoesSupportVideoMode (/* in */ BMDVideoConnection connection /* If a value of bmdVideoConnectionUnspecified is specified, the caller does not care about the connection */, /* in */ BMDDisplayMode requestedMode, /* in */ BMDPixelFormat requestedPixelFormat, /* in */ BMDVideoInputConversionMode conversionMode, /* in */ BMDSupportedVideoModeFlags flags, /* out */ BMDDisplayMode* actualMode, /* out */ bool* supported) = 0; + virtual HRESULT GetDisplayMode (/* in */ BMDDisplayMode displayMode, /* out */ IDeckLinkDisplayMode** resultDisplayMode) = 0; + virtual HRESULT GetDisplayModeIterator (/* out */ IDeckLinkDisplayModeIterator** iterator) = 0; + virtual HRESULT SetScreenPreviewCallback (/* in */ IDeckLinkScreenPreviewCallback* previewCallback) = 0; + + /* Video Input */ + + virtual HRESULT EnableVideoInput (/* in */ BMDDisplayMode displayMode, /* in */ BMDPixelFormat pixelFormat, /* in */ BMDVideoInputFlags flags) = 0; + virtual HRESULT DisableVideoInput (void) = 0; + virtual HRESULT GetAvailableVideoFrameCount (/* out */ uint32_t* availableFrameCount) = 0; + virtual HRESULT SetVideoInputFrameMemoryAllocator (/* in */ IDeckLinkMemoryAllocator* theAllocator) = 0; + + /* Audio Input */ + + virtual HRESULT EnableAudioInput (/* in */ BMDAudioSampleRate sampleRate, /* in */ BMDAudioSampleType sampleType, /* in */ uint32_t channelCount) = 0; + virtual HRESULT DisableAudioInput (void) = 0; + virtual HRESULT GetAvailableAudioSampleFrameCount (/* out */ uint32_t* availableSampleFrameCount) = 0; + + /* Input Control */ + + virtual HRESULT StartStreams (void) = 0; + virtual HRESULT StopStreams (void) = 0; + virtual HRESULT PauseStreams (void) = 0; + virtual HRESULT FlushStreams (void) = 0; + virtual HRESULT SetCallback (/* in */ IDeckLinkInputCallback_v11_5_1* theCallback) = 0; + + /* Hardware Timing */ + + virtual HRESULT GetHardwareReferenceClock (/* in */ BMDTimeScale desiredTimeScale, /* out */ BMDTimeValue* hardwareTime, /* out */ BMDTimeValue* timeInFrame, /* out */ BMDTimeValue* ticksPerFrame) = 0; + +protected: + virtual ~IDeckLinkInput_v11_5_1 () {} // call Release method to drop reference count +}; + +#endif /* defined(BMD_DECKLINKAPIVIDEOINPUT_v11_5_1_H) */ diff --git a/plugins/decklink/linux/decklink-sdk/DeckLinkAPIVideoOutput_v10_11.h b/plugins/decklink/linux/decklink-sdk/DeckLinkAPIVideoOutput_v10_11.h new file mode 100644 index 0000000..a593898 --- /dev/null +++ b/plugins/decklink/linux/decklink-sdk/DeckLinkAPIVideoOutput_v10_11.h @@ -0,0 +1,94 @@ +/* -LICENSE-START- +** Copyright (c) 2017 Blackmagic Design +** +** Permission is hereby granted, free of charge, to any person or organization +** obtaining a copy of the software and accompanying documentation covered by +** this license (the "Software") to use, reproduce, display, distribute, +** execute, and transmit the Software, and to prepare derivative works of the +** Software, and to permit third-parties to whom the Software is furnished to +** do so, all subject to the following: +** +** The copyright notices in the Software and this entire statement, including +** the above license grant, this restriction and the following disclaimer, +** must be included in all copies of the Software, in whole or in part, and +** all derivative works of the Software, unless such copies or derivative +** works are solely in the form of machine-executable object code generated by +** a source language processor. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +** SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +** FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +** DEALINGS IN THE SOFTWARE. +** -LICENSE-END- +*/ + +#ifndef BMD_DECKLINKAPIVIDEOOUTPUT_v10_11_H +#define BMD_DECKLINKAPIVIDEOOUTPUT_v10_11_H + +#include "DeckLinkAPI.h" +#include "DeckLinkAPI_v10_11.h" + +// Type Declarations +BMD_CONST REFIID IID_IDeckLinkOutput_v10_11 = /* CC5C8A6E-3F2F-4B3A-87EA-FD78AF300564 */ {0xCC,0x5C,0x8A,0x6E,0x3F,0x2F,0x4B,0x3A,0x87,0xEA,0xFD,0x78,0xAF,0x30,0x05,0x64}; + +/* Interface IDeckLinkOutput_v10_11 - DeckLink output interface. */ + +class IDeckLinkOutput_v10_11 : public IUnknown +{ +public: + virtual HRESULT DoesSupportVideoMode (/* in */ BMDDisplayMode displayMode, /* in */ BMDPixelFormat pixelFormat, /* in */ BMDVideoOutputFlags flags, /* out */ BMDDisplayModeSupport_v10_11 *result, /* out */ IDeckLinkDisplayMode **resultDisplayMode) = 0; + virtual HRESULT GetDisplayModeIterator (/* out */ IDeckLinkDisplayModeIterator **iterator) = 0; + + virtual HRESULT SetScreenPreviewCallback (/* in */ IDeckLinkScreenPreviewCallback *previewCallback) = 0; + + /* Video Output */ + + virtual HRESULT EnableVideoOutput (/* in */ BMDDisplayMode displayMode, /* in */ BMDVideoOutputFlags flags) = 0; + virtual HRESULT DisableVideoOutput (void) = 0; + + virtual HRESULT SetVideoOutputFrameMemoryAllocator (/* in */ IDeckLinkMemoryAllocator *theAllocator) = 0; + virtual HRESULT CreateVideoFrame (/* in */ int32_t width, /* in */ int32_t height, /* in */ int32_t rowBytes, /* in */ BMDPixelFormat pixelFormat, /* in */ BMDFrameFlags flags, /* out */ IDeckLinkMutableVideoFrame **outFrame) = 0; + virtual HRESULT CreateAncillaryData (/* in */ BMDPixelFormat pixelFormat, /* out */ IDeckLinkVideoFrameAncillary **outBuffer) = 0; + + virtual HRESULT DisplayVideoFrameSync (/* in */ IDeckLinkVideoFrame *theFrame) = 0; + virtual HRESULT ScheduleVideoFrame (/* in */ IDeckLinkVideoFrame *theFrame, /* in */ BMDTimeValue displayTime, /* in */ BMDTimeValue displayDuration, /* in */ BMDTimeScale timeScale) = 0; + virtual HRESULT SetScheduledFrameCompletionCallback (/* in */ IDeckLinkVideoOutputCallback *theCallback) = 0; + virtual HRESULT GetBufferedVideoFrameCount (/* out */ uint32_t *bufferedFrameCount) = 0; + + /* Audio Output */ + + virtual HRESULT EnableAudioOutput (/* in */ BMDAudioSampleRate sampleRate, /* in */ BMDAudioSampleType sampleType, /* in */ uint32_t channelCount, /* in */ BMDAudioOutputStreamType streamType) = 0; + virtual HRESULT DisableAudioOutput (void) = 0; + + virtual HRESULT WriteAudioSamplesSync (/* in */ void *buffer, /* in */ uint32_t sampleFrameCount, /* out */ uint32_t *sampleFramesWritten) = 0; + + virtual HRESULT BeginAudioPreroll (void) = 0; + virtual HRESULT EndAudioPreroll (void) = 0; + virtual HRESULT ScheduleAudioSamples (/* in */ void *buffer, /* in */ uint32_t sampleFrameCount, /* in */ BMDTimeValue streamTime, /* in */ BMDTimeScale timeScale, /* out */ uint32_t *sampleFramesWritten) = 0; + + virtual HRESULT GetBufferedAudioSampleFrameCount (/* out */ uint32_t *bufferedSampleFrameCount) = 0; + virtual HRESULT FlushBufferedAudioSamples (void) = 0; + + virtual HRESULT SetAudioCallback (/* in */ IDeckLinkAudioOutputCallback *theCallback) = 0; + + /* Output Control */ + + virtual HRESULT StartScheduledPlayback (/* in */ BMDTimeValue playbackStartTime, /* in */ BMDTimeScale timeScale, /* in */ double playbackSpeed) = 0; + virtual HRESULT StopScheduledPlayback (/* in */ BMDTimeValue stopPlaybackAtTime, /* out */ BMDTimeValue *actualStopTime, /* in */ BMDTimeScale timeScale) = 0; + virtual HRESULT IsScheduledPlaybackRunning (/* out */ bool *active) = 0; + virtual HRESULT GetScheduledStreamTime (/* in */ BMDTimeScale desiredTimeScale, /* out */ BMDTimeValue *streamTime, /* out */ double *playbackSpeed) = 0; + virtual HRESULT GetReferenceStatus (/* out */ BMDReferenceStatus *referenceStatus) = 0; + + /* Hardware Timing */ + + virtual HRESULT GetHardwareReferenceClock (/* in */ BMDTimeScale desiredTimeScale, /* out */ BMDTimeValue *hardwareTime, /* out */ BMDTimeValue *timeInFrame, /* out */ BMDTimeValue *ticksPerFrame) = 0; + virtual HRESULT GetFrameCompletionReferenceTimestamp (/* in */ IDeckLinkVideoFrame *theFrame, /* in */ BMDTimeScale desiredTimeScale, /* out */ BMDTimeValue *frameCompletionTimestamp) = 0; + +protected: + virtual ~IDeckLinkOutput_v10_11 () {} // call Release method to drop reference count +}; + +#endif /* defined(BMD_DECKLINKAPIVIDEOOUTPUT_v10_11_H) */ diff --git a/plugins/decklink/linux/decklink-sdk/DeckLinkAPIVideoOutput_v11_4.h b/plugins/decklink/linux/decklink-sdk/DeckLinkAPIVideoOutput_v11_4.h new file mode 100644 index 0000000..65de9c6 --- /dev/null +++ b/plugins/decklink/linux/decklink-sdk/DeckLinkAPIVideoOutput_v11_4.h @@ -0,0 +1,87 @@ +/* -LICENSE-START- +** Copyright (c) 2019 Blackmagic Design +** +** Permission is hereby granted, free of charge, to any person or organization +** obtaining a copy of the software and accompanying documentation covered by +** this license (the "Software") to use, reproduce, display, distribute, +** execute, and transmit the Software, and to prepare derivative works of the +** Software, and to permit third-parties to whom the Software is furnished to +** do so, all subject to the following: +** +** The copyright notices in the Software and this entire statement, including +** the above license grant, this restriction and the following disclaimer, +** must be included in all copies of the Software, in whole or in part, and +** all derivative works of the Software, unless such copies or derivative +** works are solely in the form of machine-executable object code generated by +** a source language processor. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +** SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +** FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +** DEALINGS IN THE SOFTWARE. +** -LICENSE-END- +*/ + +#ifndef BMD_DECKLINKAPIVIDEOOUTPUT_v11_4_H +#define BMD_DECKLINKAPIVIDEOOUTPUT_v11_4_H + +#include "DeckLinkAPI.h" + +// Type Declarations +BMD_CONST REFIID IID_IDeckLinkOutput_v11_4 = /* 065A0F6C-C508-4D0D-B919-F5EB0EBFC96B */ { 0x06,0x5A,0x0F,0x6C,0xC5,0x08,0x4D,0x0D,0xB9,0x19,0xF5,0xEB,0x0E,0xBF,0xC9,0x6B }; + +/* Interface IDeckLinkOutput_v11_4 - Created by QueryInterface from IDeckLink. */ + +class BMD_PUBLIC IDeckLinkOutput_v11_4 : public IUnknown +{ +public: + virtual HRESULT DoesSupportVideoMode (/* in */ BMDVideoConnection connection /* If a value of 0 is specified, the caller does not care about the connection */, /* in */ BMDDisplayMode requestedMode, /* in */ BMDPixelFormat requestedPixelFormat, /* in */ BMDSupportedVideoModeFlags flags, /* out */ BMDDisplayMode* actualMode, /* out */ bool* supported) = 0; + virtual HRESULT GetDisplayMode (/* in */ BMDDisplayMode displayMode, /* out */ IDeckLinkDisplayMode** resultDisplayMode) = 0; + virtual HRESULT GetDisplayModeIterator (/* out */ IDeckLinkDisplayModeIterator** iterator) = 0; + virtual HRESULT SetScreenPreviewCallback (/* in */ IDeckLinkScreenPreviewCallback* previewCallback) = 0; + + /* Video Output */ + + virtual HRESULT EnableVideoOutput (/* in */ BMDDisplayMode displayMode, /* in */ BMDVideoOutputFlags flags) = 0; + virtual HRESULT DisableVideoOutput (void) = 0; + virtual HRESULT SetVideoOutputFrameMemoryAllocator (/* in */ IDeckLinkMemoryAllocator* theAllocator) = 0; + virtual HRESULT CreateVideoFrame (/* in */ int32_t width, /* in */ int32_t height, /* in */ int32_t rowBytes, /* in */ BMDPixelFormat pixelFormat, /* in */ BMDFrameFlags flags, /* out */ IDeckLinkMutableVideoFrame** outFrame) = 0; + virtual HRESULT CreateAncillaryData (/* in */ BMDPixelFormat pixelFormat, /* out */ IDeckLinkVideoFrameAncillary** outBuffer) = 0; // Use of IDeckLinkVideoFrameAncillaryPackets is preferred + virtual HRESULT DisplayVideoFrameSync (/* in */ IDeckLinkVideoFrame* theFrame) = 0; + virtual HRESULT ScheduleVideoFrame (/* in */ IDeckLinkVideoFrame* theFrame, /* in */ BMDTimeValue displayTime, /* in */ BMDTimeValue displayDuration, /* in */ BMDTimeScale timeScale) = 0; + virtual HRESULT SetScheduledFrameCompletionCallback (/* in */ IDeckLinkVideoOutputCallback* theCallback) = 0; + virtual HRESULT GetBufferedVideoFrameCount (/* out */ uint32_t* bufferedFrameCount) = 0; + + /* Audio Output */ + + virtual HRESULT EnableAudioOutput (/* in */ BMDAudioSampleRate sampleRate, /* in */ BMDAudioSampleType sampleType, /* in */ uint32_t channelCount, /* in */ BMDAudioOutputStreamType streamType) = 0; + virtual HRESULT DisableAudioOutput (void) = 0; + virtual HRESULT WriteAudioSamplesSync (/* in */ void* buffer, /* in */ uint32_t sampleFrameCount, /* out */ uint32_t* sampleFramesWritten) = 0; + virtual HRESULT BeginAudioPreroll (void) = 0; + virtual HRESULT EndAudioPreroll (void) = 0; + virtual HRESULT ScheduleAudioSamples (/* in */ void* buffer, /* in */ uint32_t sampleFrameCount, /* in */ BMDTimeValue streamTime, /* in */ BMDTimeScale timeScale, /* out */ uint32_t* sampleFramesWritten) = 0; + virtual HRESULT GetBufferedAudioSampleFrameCount (/* out */ uint32_t* bufferedSampleFrameCount) = 0; + virtual HRESULT FlushBufferedAudioSamples (void) = 0; + virtual HRESULT SetAudioCallback (/* in */ IDeckLinkAudioOutputCallback* theCallback) = 0; + + /* Output Control */ + + virtual HRESULT StartScheduledPlayback (/* in */ BMDTimeValue playbackStartTime, /* in */ BMDTimeScale timeScale, /* in */ double playbackSpeed) = 0; + virtual HRESULT StopScheduledPlayback (/* in */ BMDTimeValue stopPlaybackAtTime, /* out */ BMDTimeValue* actualStopTime, /* in */ BMDTimeScale timeScale) = 0; + virtual HRESULT IsScheduledPlaybackRunning (/* out */ bool* active) = 0; + virtual HRESULT GetScheduledStreamTime (/* in */ BMDTimeScale desiredTimeScale, /* out */ BMDTimeValue* streamTime, /* out */ double* playbackSpeed) = 0; + virtual HRESULT GetReferenceStatus (/* out */ BMDReferenceStatus* referenceStatus) = 0; + + /* Hardware Timing */ + + virtual HRESULT GetHardwareReferenceClock (/* in */ BMDTimeScale desiredTimeScale, /* out */ BMDTimeValue* hardwareTime, /* out */ BMDTimeValue* timeInFrame, /* out */ BMDTimeValue* ticksPerFrame) = 0; + virtual HRESULT GetFrameCompletionReferenceTimestamp (/* in */ IDeckLinkVideoFrame* theFrame, /* in */ BMDTimeScale desiredTimeScale, /* out */ BMDTimeValue* frameCompletionTimestamp) = 0; + +protected: + virtual ~IDeckLinkOutput_v11_4 () {} // call Release method to drop reference count +}; + +#endif /* defined(BMD_DECKLINKAPIVIDEOOUTPUT_v11_4_H) */ diff --git a/plugins/decklink/linux/decklink-sdk/DeckLinkAPI_v10_11.h b/plugins/decklink/linux/decklink-sdk/DeckLinkAPI_v10_11.h new file mode 100644 index 0000000..35aa3d4 --- /dev/null +++ b/plugins/decklink/linux/decklink-sdk/DeckLinkAPI_v10_11.h @@ -0,0 +1,121 @@ +/* -LICENSE-START- +** Copyright (c) 2018 Blackmagic Design +** +** Permission is hereby granted, free of charge, to any person or organization +** obtaining a copy of the software and accompanying documentation covered by +** this license (the "Software") to use, reproduce, display, distribute, +** execute, and transmit the Software, and to prepare derivative works of the +** Software, and to permit third-parties to whom the Software is furnished to +** do so, all subject to the following: +** +** The copyright notices in the Software and this entire statement, including +** the above license grant, this restriction and the following disclaimer, +** must be included in all copies of the Software, in whole or in part, and +** all derivative works of the Software, unless such copies or derivative +** works are solely in the form of machine-executable object code generated by +** a source language processor. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +** SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +** FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +** DEALINGS IN THE SOFTWARE. +** -LICENSE-END- +*/ + +#ifndef BMD_DECKLINKAPI_v10_11_H +#define BMD_DECKLINKAPI_v10_11_H + +#include "DeckLinkAPI.h" + +// Interface ID Declarations + +BMD_CONST REFIID IID_IDeckLinkAttributes_v10_11 = /* ABC11843-D966-44CB-96E2-A1CB5D3135C4 */ {0xAB,0xC1,0x18,0x43,0xD9,0x66,0x44,0xCB,0x96,0xE2,0xA1,0xCB,0x5D,0x31,0x35,0xC4}; +BMD_CONST REFIID IID_IDeckLinkNotification_v10_11 = /* 0A1FB207-E215-441B-9B19-6FA1575946C5 */ {0x0A,0x1F,0xB2,0x07,0xE2,0x15,0x44,0x1B,0x9B,0x19,0x6F,0xA1,0x57,0x59,0x46,0xC5}; + +/* Enum BMDDisplayModeSupport_v10_11 - Output mode supported flags */ + +typedef uint32_t BMDDisplayModeSupport_v10_11; +enum _BMDDisplayModeSupport_v10_11 { + bmdDisplayModeNotSupported_v10_11 = 0, + bmdDisplayModeSupported_v10_11, + bmdDisplayModeSupportedWithConversion_v10_11 +}; + +/* Enum BMDDuplexMode_v10_11 - Duplex for configurable ports */ + +typedef uint32_t BMDDuplexMode_v10_11; +enum _BMDDuplexMode_v10_11 { + bmdDuplexModeFull_v10_11 = /* 'fdup' */ 0x66647570, + bmdDuplexModeHalf_v10_11 = /* 'hdup' */ 0x68647570 +}; + +/* Enum BMDDeckLinkAttributeID_v10_11 - DeckLink Attribute ID */ + +enum _BMDDeckLinkAttributeID_v10_11 { + + /* Flags */ + + BMDDeckLinkSupportsDuplexModeConfiguration_v10_11 = 'dupx', + BMDDeckLinkSupportsHDKeying_v10_11 = 'keyh', + + /* Integers */ + + BMDDeckLinkPairedDevicePersistentID_v10_11 = 'ppid', + BMDDeckLinkSupportsFullDuplex_v10_11 = 'fdup', +}; + +enum _BMDDeckLinkStatusID_v10_11 { + bmdDeckLinkStatusDuplexMode_v10_11 = 'dupx', +}; + +typedef uint32_t BMDDuplexStatus_v10_11; +enum _BMDDuplexStatus_v10_11 { + bmdDuplexFullDuplex_v10_11 = 'fdup', + bmdDuplexHalfDuplex_v10_11 = 'hdup', + bmdDuplexSimplex_v10_11 = 'splx', + bmdDuplexInactive_v10_11 = 'inac', +}; + +#if defined(__cplusplus) + +/* Interface IDeckLinkAttributes_v10_11 - DeckLink Attribute interface */ + +class BMD_PUBLIC IDeckLinkAttributes_v10_11 : public IUnknown +{ +public: + virtual HRESULT GetFlag (/* in */ BMDDeckLinkAttributeID cfgID, /* out */ bool *value) = 0; + virtual HRESULT GetInt (/* in */ BMDDeckLinkAttributeID cfgID, /* out */ int64_t *value) = 0; + virtual HRESULT GetFloat (/* in */ BMDDeckLinkAttributeID cfgID, /* out */ double *value) = 0; + virtual HRESULT GetString (/* in */ BMDDeckLinkAttributeID cfgID, /* out */ const char **value) = 0; + +protected: + virtual ~IDeckLinkAttributes_v10_11 () {} // call Release method to drop reference count +}; + +/* Interface IDeckLinkNotification_v10_11 - DeckLink Notification interface */ + +class BMD_PUBLIC IDeckLinkNotification_v10_11 : public IUnknown +{ +public: + virtual HRESULT Subscribe (/* in */ BMDNotifications topic, /* in */ IDeckLinkNotificationCallback *theCallback) = 0; + virtual HRESULT Unsubscribe (/* in */ BMDNotifications topic, /* in */ IDeckLinkNotificationCallback *theCallback) = 0; +}; + +/* Functions */ + +extern "C" { + + IDeckLinkIterator* BMD_PUBLIC CreateDeckLinkIteratorInstance_v10_11 (void); + IDeckLinkDiscovery* BMD_PUBLIC CreateDeckLinkDiscoveryInstance_v10_11 (void); + IDeckLinkAPIInformation* BMD_PUBLIC CreateDeckLinkAPIInformationInstance_v10_11 (void); + IDeckLinkGLScreenPreviewHelper* BMD_PUBLIC CreateOpenGLScreenPreviewHelper_v10_11 (void); + IDeckLinkVideoConversion* BMD_PUBLIC CreateVideoConversionInstance_v10_11 (void); + IDeckLinkVideoFrameAncillaryPackets* BMD_PUBLIC CreateVideoFrameAncillaryPacketsInstance_v10_11 (void); // For use when creating a custom IDeckLinkVideoFrame without wrapping IDeckLinkOutput::CreateVideoFrame + +} + +#endif // defined(__cplusplus) +#endif /* defined(BMD_DECKLINKAPI_v10_11_H) */ diff --git a/plugins/decklink/linux/decklink-sdk/DeckLinkAPI_v11_5.h b/plugins/decklink/linux/decklink-sdk/DeckLinkAPI_v11_5.h new file mode 100644 index 0000000..ad2df1f --- /dev/null +++ b/plugins/decklink/linux/decklink-sdk/DeckLinkAPI_v11_5.h @@ -0,0 +1,100 @@ +/* -LICENSE-START- +** Copyright (c) 2020 Blackmagic Design +** +** Permission is hereby granted, free of charge, to any person or organization +** obtaining a copy of the software and accompanying documentation covered by +** this license (the "Software") to use, reproduce, display, distribute, +** execute, and transmit the Software, and to prepare derivative works of the +** Software, and to permit third-parties to whom the Software is furnished to +** do so, all subject to the following: +** +** The copyright notices in the Software and this entire statement, including +** the above license grant, this restriction and the following disclaimer, +** must be included in all copies of the Software, in whole or in part, and +** all derivative works of the Software, unless such copies or derivative +** works are solely in the form of machine-executable object code generated by +** a source language processor. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +** SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +** FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +** DEALINGS IN THE SOFTWARE. +** -LICENSE-END- +*/ + +#ifndef BMD_DECKLINKAPI_v11_5_H +#define BMD_DECKLINKAPI_v11_5_H + +#include "DeckLinkAPI.h" + +BMD_CONST REFIID IID_IDeckLinkVideoFrameMetadataExtensions_v11_5 = /* D5973DC9-6432-46D0-8F0B-2496F8A1238F */ {0xD5,0x97,0x3D,0xC9,0x64,0x32,0x46,0xD0,0x8F,0x0B,0x24,0x96,0xF8,0xA1,0x23,0x8F}; + +/* Enum BMDDeckLinkFrameMetadataID - DeckLink Frame Metadata ID */ + +typedef uint32_t BMDDeckLinkFrameMetadataID_v11_5; +enum _BMDDeckLinkFrameMetadataID_v11_5 { + bmdDeckLinkFrameMetadataCintelFilmType_v11_5 = /* 'cfty' */ 0x63667479, // Current film type + bmdDeckLinkFrameMetadataCintelFilmGauge_v11_5 = /* 'cfga' */ 0x63666761, // Current film gauge + bmdDeckLinkFrameMetadataCintelKeykodeLow_v11_5 = /* 'ckkl' */ 0x636B6B6C, // Raw keykode value - low 64 bits + bmdDeckLinkFrameMetadataCintelKeykodeHigh_v11_5 = /* 'ckkh' */ 0x636B6B68, // Raw keykode value - high 64 bits + bmdDeckLinkFrameMetadataCintelTile1Size_v11_5 = /* 'ct1s' */ 0x63743173, // Size in bytes of compressed raw tile 1 + bmdDeckLinkFrameMetadataCintelTile2Size_v11_5 = /* 'ct2s' */ 0x63743273, // Size in bytes of compressed raw tile 2 + bmdDeckLinkFrameMetadataCintelTile3Size_v11_5 = /* 'ct3s' */ 0x63743373, // Size in bytes of compressed raw tile 3 + bmdDeckLinkFrameMetadataCintelTile4Size_v11_5 = /* 'ct4s' */ 0x63743473, // Size in bytes of compressed raw tile 4 + bmdDeckLinkFrameMetadataCintelImageWidth_v11_5 = /* 'IWPx' */ 0x49575078, // Width in pixels of image + bmdDeckLinkFrameMetadataCintelImageHeight_v11_5 = /* 'IHPx' */ 0x49485078, // Height in pixels of image + bmdDeckLinkFrameMetadataCintelLinearMaskingRedInRed_v11_5 = /* 'mrir' */ 0x6D726972, // Red in red linear masking parameter + bmdDeckLinkFrameMetadataCintelLinearMaskingGreenInRed_v11_5 = /* 'mgir' */ 0x6D676972, // Green in red linear masking parameter + bmdDeckLinkFrameMetadataCintelLinearMaskingBlueInRed_v11_5 = /* 'mbir' */ 0x6D626972, // Blue in red linear masking parameter + bmdDeckLinkFrameMetadataCintelLinearMaskingRedInGreen_v11_5 = /* 'mrig' */ 0x6D726967, // Red in green linear masking parameter + bmdDeckLinkFrameMetadataCintelLinearMaskingGreenInGreen_v11_5 = /* 'mgig' */ 0x6D676967, // Green in green linear masking parameter + bmdDeckLinkFrameMetadataCintelLinearMaskingBlueInGreen_v11_5 = /* 'mbig' */ 0x6D626967, // Blue in green linear masking parameter + bmdDeckLinkFrameMetadataCintelLinearMaskingRedInBlue_v11_5 = /* 'mrib' */ 0x6D726962, // Red in blue linear masking parameter + bmdDeckLinkFrameMetadataCintelLinearMaskingGreenInBlue_v11_5 = /* 'mgib' */ 0x6D676962, // Green in blue linear masking parameter + bmdDeckLinkFrameMetadataCintelLinearMaskingBlueInBlue_v11_5 = /* 'mbib' */ 0x6D626962, // Blue in blue linear masking parameter + bmdDeckLinkFrameMetadataCintelLogMaskingRedInRed_v11_5 = /* 'mlrr' */ 0x6D6C7272, // Red in red log masking parameter + bmdDeckLinkFrameMetadataCintelLogMaskingGreenInRed_v11_5 = /* 'mlgr' */ 0x6D6C6772, // Green in red log masking parameter + bmdDeckLinkFrameMetadataCintelLogMaskingBlueInRed_v11_5 = /* 'mlbr' */ 0x6D6C6272, // Blue in red log masking parameter + bmdDeckLinkFrameMetadataCintelLogMaskingRedInGreen_v11_5 = /* 'mlrg' */ 0x6D6C7267, // Red in green log masking parameter + bmdDeckLinkFrameMetadataCintelLogMaskingGreenInGreen_v11_5 = /* 'mlgg' */ 0x6D6C6767, // Green in green log masking parameter + bmdDeckLinkFrameMetadataCintelLogMaskingBlueInGreen_v11_5 = /* 'mlbg' */ 0x6D6C6267, // Blue in green log masking parameter + bmdDeckLinkFrameMetadataCintelLogMaskingRedInBlue_v11_5 = /* 'mlrb' */ 0x6D6C7262, // Red in blue log masking parameter + bmdDeckLinkFrameMetadataCintelLogMaskingGreenInBlue_v11_5 = /* 'mlgb' */ 0x6D6C6762, // Green in blue log masking parameter + bmdDeckLinkFrameMetadataCintelLogMaskingBlueInBlue_v11_5 = /* 'mlbb' */ 0x6D6C6262, // Blue in blue log masking parameter + bmdDeckLinkFrameMetadataCintelFilmFrameRate_v11_5 = /* 'cffr' */ 0x63666672, // Film frame rate + bmdDeckLinkFrameMetadataCintelOffsetToApplyHorizontal_v11_5 = /* 'otah' */ 0x6F746168, // Horizontal offset (pixels) to be applied to image + bmdDeckLinkFrameMetadataCintelOffsetToApplyVertical_v11_5 = /* 'otav' */ 0x6F746176, // Vertical offset (pixels) to be applied to image + bmdDeckLinkFrameMetadataCintelGainRed_v11_5 = /* 'LfRd' */ 0x4C665264, // Red gain parameter to apply after log + bmdDeckLinkFrameMetadataCintelGainGreen_v11_5 = /* 'LfGr' */ 0x4C664772, // Green gain parameter to apply after log + bmdDeckLinkFrameMetadataCintelGainBlue_v11_5 = /* 'LfBl' */ 0x4C66426C, // Blue gain parameter to apply after log + bmdDeckLinkFrameMetadataCintelLiftRed_v11_5 = /* 'GnRd' */ 0x476E5264, // Red lift parameter to apply after log and gain + bmdDeckLinkFrameMetadataCintelLiftGreen_v11_5 = /* 'GnGr' */ 0x476E4772, // Green lift parameter to apply after log and gain + bmdDeckLinkFrameMetadataCintelLiftBlue_v11_5 = /* 'GnBl' */ 0x476E426C, // Blue lift parameter to apply after log and gain + bmdDeckLinkFrameMetadataCintelHDRGainRed_v11_5 = /* 'HGRd' */ 0x48475264, // Red gain parameter to apply to linear data for HDR Combination + bmdDeckLinkFrameMetadataCintelHDRGainGreen_v11_5 = /* 'HGGr' */ 0x48474772, // Green gain parameter to apply to linear data for HDR Combination + bmdDeckLinkFrameMetadataCintelHDRGainBlue_v11_5 = /* 'HGBl' */ 0x4847426C, // Blue gain parameter to apply to linear data for HDR Combination + bmdDeckLinkFrameMetadataCintel16mmCropRequired_v11_5 = /* 'c16c' */ 0x63313663, // The image should be cropped to 16mm size + bmdDeckLinkFrameMetadataCintelInversionRequired_v11_5 = /* 'cinv' */ 0x63696E76, // The image should be colour inverted + bmdDeckLinkFrameMetadataCintelFlipRequired_v11_5 = /* 'cflr' */ 0x63666C72, // The image should be flipped horizontally + bmdDeckLinkFrameMetadataCintelFocusAssistEnabled_v11_5 = /* 'cfae' */ 0x63666165, // Focus Assist is currently enabled + bmdDeckLinkFrameMetadataCintelKeykodeIsInterpolated_v11_5 = /* 'kkii' */ 0x6B6B6969 // The keykode for this frame is interpolated from nearby keykodes +}; + +/* Interface IDeckLinkVideoFrameMetadataExtensions - Optional interface implemented on IDeckLinkVideoFrame to support frame metadata such as HDMI HDR information */ + +class BMD_PUBLIC IDeckLinkVideoFrameMetadataExtensions_v11_5 : public IUnknown +{ +public: + virtual HRESULT GetInt (/* in */ BMDDeckLinkFrameMetadataID_v11_5 metadataID, /* out */ int64_t *value) = 0; + virtual HRESULT GetFloat (/* in */ BMDDeckLinkFrameMetadataID_v11_5 metadataID, /* out */ double *value) = 0; + virtual HRESULT GetFlag (/* in */ BMDDeckLinkFrameMetadataID_v11_5 metadataID, /* out */ bool* value) = 0; + virtual HRESULT GetString (/* in */ BMDDeckLinkFrameMetadataID_v11_5 metadataID, /* out */ const char **value) = 0; + +protected: + virtual ~IDeckLinkVideoFrameMetadataExtensions_v11_5 () {} // call Release method to drop reference count +}; + +#endif /* defined(BMD_DECKLINKAPI_v11_5_H) */ diff --git a/plugins/decklink/linux/decklink-sdk/DeckLinkAPI_v11_5_1.h b/plugins/decklink/linux/decklink-sdk/DeckLinkAPI_v11_5_1.h new file mode 100644 index 0000000..35d3477 --- /dev/null +++ b/plugins/decklink/linux/decklink-sdk/DeckLinkAPI_v11_5_1.h @@ -0,0 +1,44 @@ +/* -LICENSE-START- +** Copyright (c) 2020 Blackmagic Design +** +** Permission is hereby granted, free of charge, to any person or organization +** obtaining a copy of the software and accompanying documentation covered by +** this license (the "Software") to use, reproduce, display, distribute, +** execute, and transmit the Software, and to prepare derivative works of the +** Software, and to permit third-parties to whom the Software is furnished to +** do so, all subject to the following: +** +** The copyright notices in the Software and this entire statement, including +** the above license grant, this restriction and the following disclaimer, +** must be included in all copies of the Software, in whole or in part, and +** all derivative works of the Software, unless such copies or derivative +** works are solely in the form of machine-executable object code generated by +** a source language processor. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +** SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +** FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +** DEALINGS IN THE SOFTWARE. +** -LICENSE-END- +*/ + +#ifndef BMD_DECKLINKAPI_v11_5_1_H +#define BMD_DECKLINKAPI_v11_5_1_H + +#include "DeckLinkAPI.h" + +/* Enum BMDDeckLinkStatusID - DeckLink Status ID */ + +typedef uint32_t BMDDeckLinkStatusID_v11_5_1; +enum _BMDDeckLinkStatusID_v11_5_1 { + + /* Video output flags */ + + bmdDeckLinkStatusDetectedVideoInputFlags_v11_5_1 = /* 'dvif' */ 0x64766966, + +}; + +#endif /* defined(BMD_DECKLINKAPI_v11_5_1_H) */ diff --git a/plugins/decklink/linux/decklink-sdk/DeckLinkAPI_v7_1.h b/plugins/decklink/linux/decklink-sdk/DeckLinkAPI_v7_1.h index b0c637c..beb3a32 100644 --- a/plugins/decklink/linux/decklink-sdk/DeckLinkAPI_v7_1.h +++ b/plugins/decklink/linux/decklink-sdk/DeckLinkAPI_v7_1.h @@ -30,6 +30,7 @@ #define __DeckLink_API_v7_1_h__ #include "DeckLinkAPI.h" +#include "DeckLinkAPI_v10_11.h" // "B28131B6-59AC-4857-B5AC-CD75D5883E2F" #define IID_IDeckLinkDisplayModeIterator_v7_1 (REFIID){0xB2,0x81,0x31,0xB6,0x59,0xAC,0x48,0x57,0xB5,0xAC,0xCD,0x75,0xD5,0x88,0x3E,0x2F} @@ -100,7 +101,7 @@ class BMD_PUBLIC IDeckLinkOutput_v7_1 : public IUnknown { public: // Display mode predicates - virtual HRESULT STDMETHODCALLTYPE DoesSupportVideoMode (BMDDisplayMode displayMode, BMDPixelFormat pixelFormat, BMDDisplayModeSupport *result) = 0; + virtual HRESULT STDMETHODCALLTYPE DoesSupportVideoMode (BMDDisplayMode displayMode, BMDPixelFormat pixelFormat, BMDDisplayModeSupport_v10_11 *result) = 0; virtual HRESULT STDMETHODCALLTYPE GetDisplayModeIterator (IDeckLinkDisplayModeIterator_v7_1* *iterator) = 0; @@ -143,7 +144,7 @@ public: class BMD_PUBLIC IDeckLinkInput_v7_1 : public IUnknown { public: - virtual HRESULT STDMETHODCALLTYPE DoesSupportVideoMode (BMDDisplayMode displayMode, BMDPixelFormat pixelFormat, BMDDisplayModeSupport *result) = 0; + virtual HRESULT STDMETHODCALLTYPE DoesSupportVideoMode (BMDDisplayMode displayMode, BMDPixelFormat pixelFormat, BMDDisplayModeSupport_v10_11 *result) = 0; virtual HRESULT STDMETHODCALLTYPE GetDisplayModeIterator (IDeckLinkDisplayModeIterator_v7_1 **iterator) = 0; // Video input diff --git a/plugins/decklink/linux/decklink-sdk/DeckLinkAPI_v7_3.h b/plugins/decklink/linux/decklink-sdk/DeckLinkAPI_v7_3.h index bb3192e..fed1b5f 100644 --- a/plugins/decklink/linux/decklink-sdk/DeckLinkAPI_v7_3.h +++ b/plugins/decklink/linux/decklink-sdk/DeckLinkAPI_v7_3.h @@ -32,6 +32,7 @@ #include "DeckLinkAPI.h" #include "DeckLinkAPI_v7_6.h" +#include "DeckLinkAPI_v10_11.h" /* Interface ID Declarations */ @@ -56,7 +57,7 @@ class IDeckLinkVideoInputFrame_v7_3; class BMD_PUBLIC IDeckLinkOutput_v7_3 : public IUnknown { public: - virtual HRESULT DoesSupportVideoMode (BMDDisplayMode displayMode, BMDPixelFormat pixelFormat, /* out */ BMDDisplayModeSupport *result) = 0; + virtual HRESULT DoesSupportVideoMode (BMDDisplayMode displayMode, BMDPixelFormat pixelFormat, /* out */ BMDDisplayModeSupport_v10_11 *result) = 0; virtual HRESULT GetDisplayModeIterator (/* out */ IDeckLinkDisplayModeIterator_v7_6 **iterator) = 0; virtual HRESULT SetScreenPreviewCallback (/* in */ IDeckLinkScreenPreviewCallback *previewCallback) = 0; @@ -125,7 +126,7 @@ protected: class BMD_PUBLIC IDeckLinkInput_v7_3 : public IUnknown { public: - virtual HRESULT DoesSupportVideoMode (BMDDisplayMode displayMode, BMDPixelFormat pixelFormat, /* out */ BMDDisplayModeSupport *result) = 0; + virtual HRESULT DoesSupportVideoMode (BMDDisplayMode displayMode, BMDPixelFormat pixelFormat, /* out */ BMDDisplayModeSupport_v10_11 *result) = 0; virtual HRESULT GetDisplayModeIterator (/* out */ IDeckLinkDisplayModeIterator_v7_6 **iterator) = 0; virtual HRESULT SetScreenPreviewCallback (/* in */ IDeckLinkScreenPreviewCallback *previewCallback) = 0; diff --git a/plugins/decklink/linux/decklink-sdk/DeckLinkAPI_v7_6.h b/plugins/decklink/linux/decklink-sdk/DeckLinkAPI_v7_6.h index d981206..547ba99 100644 --- a/plugins/decklink/linux/decklink-sdk/DeckLinkAPI_v7_6.h +++ b/plugins/decklink/linux/decklink-sdk/DeckLinkAPI_v7_6.h @@ -31,6 +31,7 @@ #define __DeckLink_API_v7_6_h__ #include "DeckLinkAPI.h" +#include "DeckLinkAPI_v10_11.h" // Interface ID Declarations @@ -141,7 +142,7 @@ protected: class BMD_PUBLIC IDeckLinkOutput_v7_6 : public IUnknown { public: - virtual HRESULT DoesSupportVideoMode (/* in */ BMDDisplayMode displayMode, /* in */ BMDPixelFormat pixelFormat, /* out */ BMDDisplayModeSupport *result) = 0; + virtual HRESULT DoesSupportVideoMode (/* in */ BMDDisplayMode displayMode, /* in */ BMDPixelFormat pixelFormat, /* out */ BMDDisplayModeSupport_v10_11 *result) = 0; virtual HRESULT GetDisplayModeIterator (/* out */ IDeckLinkDisplayModeIterator_v7_6 **iterator) = 0; virtual HRESULT SetScreenPreviewCallback (/* in */ IDeckLinkScreenPreviewCallback_v7_6 *previewCallback) = 0; @@ -197,7 +198,7 @@ protected: class BMD_PUBLIC IDeckLinkInput_v7_6 : public IUnknown { public: - virtual HRESULT DoesSupportVideoMode (/* in */ BMDDisplayMode displayMode, /* in */ BMDPixelFormat pixelFormat, /* out */ BMDDisplayModeSupport *result) = 0; + virtual HRESULT DoesSupportVideoMode (/* in */ BMDDisplayMode displayMode, /* in */ BMDPixelFormat pixelFormat, /* out */ BMDDisplayModeSupport_v10_11 *result) = 0; virtual HRESULT GetDisplayModeIterator (/* out */ IDeckLinkDisplayModeIterator_v7_6 **iterator) = 0; virtual HRESULT SetScreenPreviewCallback (/* in */ IDeckLinkScreenPreviewCallback_v7_6 *previewCallback) = 0; diff --git a/plugins/decklink/linux/decklink-sdk/DeckLinkAPI_v9_2.h b/plugins/decklink/linux/decklink-sdk/DeckLinkAPI_v9_2.h index dd5f83f..cb2d3d3 100644 --- a/plugins/decklink/linux/decklink-sdk/DeckLinkAPI_v9_2.h +++ b/plugins/decklink/linux/decklink-sdk/DeckLinkAPI_v9_2.h @@ -29,6 +29,7 @@ #define BMD_DECKLINKAPI_v9_2_H #include "DeckLinkAPI.h" +#include "DeckLinkAPI_v10_11.h" // Interface ID Declarations @@ -43,7 +44,7 @@ class BMD_PUBLIC IDeckLinkInput_v9_2 : public IUnknown { public: - virtual HRESULT DoesSupportVideoMode (/* in */ BMDDisplayMode displayMode, /* in */ BMDPixelFormat pixelFormat, /* in */ BMDVideoInputFlags flags, /* out */ BMDDisplayModeSupport *result, /* out */ IDeckLinkDisplayMode **resultDisplayMode) = 0; + virtual HRESULT DoesSupportVideoMode (/* in */ BMDDisplayMode displayMode, /* in */ BMDPixelFormat pixelFormat, /* in */ BMDVideoInputFlags flags, /* out */ BMDDisplayModeSupport_v10_11 *result, /* out */ IDeckLinkDisplayMode **resultDisplayMode) = 0; virtual HRESULT GetDisplayModeIterator (/* out */ IDeckLinkDisplayModeIterator **iterator) = 0; virtual HRESULT SetScreenPreviewCallback (/* in */ IDeckLinkScreenPreviewCallback *previewCallback) = 0; diff --git a/plugins/decklink/linux/decklink-sdk/DeckLinkAPI_v9_9.h b/plugins/decklink/linux/decklink-sdk/DeckLinkAPI_v9_9.h index 9a51bf2..501d16c 100644 --- a/plugins/decklink/linux/decklink-sdk/DeckLinkAPI_v9_9.h +++ b/plugins/decklink/linux/decklink-sdk/DeckLinkAPI_v9_9.h @@ -29,6 +29,7 @@ #define BMD_DECKLINKAPI_v9_9_H #include "DeckLinkAPI.h" +#include "DeckLinkAPI_v10_11.h" // Interface ID Declarations @@ -43,7 +44,7 @@ class BMD_PUBLIC IDeckLinkOutput_v9_9 : public IUnknown { public: - virtual HRESULT DoesSupportVideoMode (/* in */ BMDDisplayMode displayMode, /* in */ BMDPixelFormat pixelFormat, /* in */ BMDVideoOutputFlags flags, /* out */ BMDDisplayModeSupport *result, /* out */ IDeckLinkDisplayMode **resultDisplayMode) = 0; + virtual HRESULT DoesSupportVideoMode (/* in */ BMDDisplayMode displayMode, /* in */ BMDPixelFormat pixelFormat, /* in */ BMDVideoOutputFlags flags, /* out */ BMDDisplayModeSupport_v10_11 *result, /* out */ IDeckLinkDisplayMode **resultDisplayMode) = 0; virtual HRESULT GetDisplayModeIterator (/* out */ IDeckLinkDisplayModeIterator **iterator) = 0; virtual HRESULT SetScreenPreviewCallback (/* in */ IDeckLinkScreenPreviewCallback *previewCallback) = 0; diff --git a/plugins/decklink/mac/CMakeLists.txt b/plugins/decklink/mac/CMakeLists.txt index adfd592..889b61f 100644 --- a/plugins/decklink/mac/CMakeLists.txt +++ b/plugins/decklink/mac/CMakeLists.txt @@ -9,6 +9,8 @@ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}") find_library(COREFOUNDATION CoreFoundation) +include_directories(${CMAKE_SOURCE_DIR}/deps/libcaption) + set(mac-decklink-sdk_HEADERS decklink-sdk/DeckLinkAPI.h decklink-sdk/DeckLinkAPIConfiguration.h @@ -37,6 +39,7 @@ set(mac-decklink_HEADERS ../audio-repack.h ../audio-repack.hpp ../util.hpp + ../OBSVideoFrame.h ) set(mac-decklink_SOURCES @@ -54,6 +57,7 @@ set(mac-decklink_SOURCES ../audio-repack.c platform.cpp ../util.cpp + ../OBSVideoFrame.cpp ) list(APPEND decklink_HEADERS ${decklink_UI_HEADERS}) @@ -73,7 +77,9 @@ add_library(mac-decklink MODULE target_link_libraries(mac-decklink libobs - ${COREFOUNDATION}) -set_target_properties(mac-decklink PROPERTIES FOLDER "plugins") + obs-frontend-api + ${COREFOUNDATION} + caption) +set_target_properties(mac-decklink PROPERTIES FOLDER "plugins/decklink") install_obs_plugin_with_data(mac-decklink ../data) diff --git a/plugins/decklink/mac/decklink-sdk/DeckLinkAPI.h b/plugins/decklink/mac/decklink-sdk/DeckLinkAPI.h index 368a72b..98e43f5 100644 --- a/plugins/decklink/mac/decklink-sdk/DeckLinkAPI.h +++ b/plugins/decklink/mac/decklink-sdk/DeckLinkAPI.h @@ -1,5 +1,5 @@ /* -LICENSE-START- -** Copyright (c) 2018 Blackmagic Design +** Copyright (c) 2020 Blackmagic Design ** ** Permission is hereby granted, free of charge, to any person or organization ** obtaining a copy of the software and accompanying documentation covered by @@ -7,14 +7,14 @@ ** execute, and transmit the Software, and to prepare derivative works of the ** Software, and to permit third-parties to whom the Software is furnished to ** do so, all subject to the following: -** +** ** The copyright notices in the Software and this entire statement, including ** the above license grant, this restriction and the following disclaimer, ** must be included in all copies of the Software, in whole or in part, and ** all derivative works of the Software, unless such copies or derivative ** works are solely in the form of machine-executable object code generated by ** a source language processor. -** +** ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT @@ -62,42 +62,46 @@ // Interface ID Declarations -BMD_CONST REFIID IID_IDeckLinkVideoOutputCallback = /* 20AA5225-1958-47CB-820B-80A8D521A6EE */ {0x20,0xAA,0x52,0x25,0x19,0x58,0x47,0xCB,0x82,0x0B,0x80,0xA8,0xD5,0x21,0xA6,0xEE}; -BMD_CONST REFIID IID_IDeckLinkInputCallback = /* DD04E5EC-7415-42AB-AE4A-E80C4DFC044A */ {0xDD,0x04,0xE5,0xEC,0x74,0x15,0x42,0xAB,0xAE,0x4A,0xE8,0x0C,0x4D,0xFC,0x04,0x4A}; -BMD_CONST REFIID IID_IDeckLinkEncoderInputCallback = /* ACF13E61-F4A0-4974-A6A7-59AFF6268B31 */ {0xAC,0xF1,0x3E,0x61,0xF4,0xA0,0x49,0x74,0xA6,0xA7,0x59,0xAF,0xF6,0x26,0x8B,0x31}; -BMD_CONST REFIID IID_IDeckLinkMemoryAllocator = /* B36EB6E7-9D29-4AA8-92EF-843B87A289E8 */ {0xB3,0x6E,0xB6,0xE7,0x9D,0x29,0x4A,0xA8,0x92,0xEF,0x84,0x3B,0x87,0xA2,0x89,0xE8}; -BMD_CONST REFIID IID_IDeckLinkAudioOutputCallback = /* 403C681B-7F46-4A12-B993-2BB127084EE6 */ {0x40,0x3C,0x68,0x1B,0x7F,0x46,0x4A,0x12,0xB9,0x93,0x2B,0xB1,0x27,0x08,0x4E,0xE6}; -BMD_CONST REFIID IID_IDeckLinkIterator = /* 50FB36CD-3063-4B73-BDBB-958087F2D8BA */ {0x50,0xFB,0x36,0xCD,0x30,0x63,0x4B,0x73,0xBD,0xBB,0x95,0x80,0x87,0xF2,0xD8,0xBA}; -BMD_CONST REFIID IID_IDeckLinkAPIInformation = /* 7BEA3C68-730D-4322-AF34-8A7152B532A4 */ {0x7B,0xEA,0x3C,0x68,0x73,0x0D,0x43,0x22,0xAF,0x34,0x8A,0x71,0x52,0xB5,0x32,0xA4}; -BMD_CONST REFIID IID_IDeckLinkOutput = /* CC5C8A6E-3F2F-4B3A-87EA-FD78AF300564 */ {0xCC,0x5C,0x8A,0x6E,0x3F,0x2F,0x4B,0x3A,0x87,0xEA,0xFD,0x78,0xAF,0x30,0x05,0x64}; -BMD_CONST REFIID IID_IDeckLinkInput = /* AF22762B-DFAC-4846-AA79-FA8883560995 */ {0xAF,0x22,0x76,0x2B,0xDF,0xAC,0x48,0x46,0xAA,0x79,0xFA,0x88,0x83,0x56,0x09,0x95}; -BMD_CONST REFIID IID_IDeckLinkHDMIInputEDID = /* ABBBACBC-45BC-4665-9D92-ACE6E5A97902 */ {0xAB,0xBB,0xAC,0xBC,0x45,0xBC,0x46,0x65,0x9D,0x92,0xAC,0xE6,0xE5,0xA9,0x79,0x02}; -BMD_CONST REFIID IID_IDeckLinkEncoderInput = /* 270587DA-6B7D-42E7-A1F0-6D853F581185 */ {0x27,0x05,0x87,0xDA,0x6B,0x7D,0x42,0xE7,0xA1,0xF0,0x6D,0x85,0x3F,0x58,0x11,0x85}; -BMD_CONST REFIID IID_IDeckLinkVideoFrame = /* 3F716FE0-F023-4111-BE5D-EF4414C05B17 */ {0x3F,0x71,0x6F,0xE0,0xF0,0x23,0x41,0x11,0xBE,0x5D,0xEF,0x44,0x14,0xC0,0x5B,0x17}; -BMD_CONST REFIID IID_IDeckLinkMutableVideoFrame = /* 69E2639F-40DA-4E19-B6F2-20ACE815C390 */ {0x69,0xE2,0x63,0x9F,0x40,0xDA,0x4E,0x19,0xB6,0xF2,0x20,0xAC,0xE8,0x15,0xC3,0x90}; -BMD_CONST REFIID IID_IDeckLinkVideoFrame3DExtensions = /* DA0F7E4A-EDC7-48A8-9CDD-2DB51C729CD7 */ {0xDA,0x0F,0x7E,0x4A,0xED,0xC7,0x48,0xA8,0x9C,0xDD,0x2D,0xB5,0x1C,0x72,0x9C,0xD7}; -BMD_CONST REFIID IID_IDeckLinkVideoFrameMetadataExtensions = /* D5973DC9-6432-46D0-8F0B-2496F8A1238F */ {0xD5,0x97,0x3D,0xC9,0x64,0x32,0x46,0xD0,0x8F,0x0B,0x24,0x96,0xF8,0xA1,0x23,0x8F}; -BMD_CONST REFIID IID_IDeckLinkVideoInputFrame = /* 05CFE374-537C-4094-9A57-680525118F44 */ {0x05,0xCF,0xE3,0x74,0x53,0x7C,0x40,0x94,0x9A,0x57,0x68,0x05,0x25,0x11,0x8F,0x44}; -BMD_CONST REFIID IID_IDeckLinkAncillaryPacket = /* CC5BBF7E-029C-4D3B-9158-6000EF5E3670 */ {0xCC,0x5B,0xBF,0x7E,0x02,0x9C,0x4D,0x3B,0x91,0x58,0x60,0x00,0xEF,0x5E,0x36,0x70}; -BMD_CONST REFIID IID_IDeckLinkAncillaryPacketIterator = /* 3FC8994B-88FB-4C17-968F-9AAB69D964A7 */ {0x3F,0xC8,0x99,0x4B,0x88,0xFB,0x4C,0x17,0x96,0x8F,0x9A,0xAB,0x69,0xD9,0x64,0xA7}; -BMD_CONST REFIID IID_IDeckLinkVideoFrameAncillaryPackets = /* 6C186C0F-459E-41D8-AEE2-4812D81AEE68 */ {0x6C,0x18,0x6C,0x0F,0x45,0x9E,0x41,0xD8,0xAE,0xE2,0x48,0x12,0xD8,0x1A,0xEE,0x68}; -BMD_CONST REFIID IID_IDeckLinkVideoFrameAncillary = /* 732E723C-D1A4-4E29-9E8E-4A88797A0004 */ {0x73,0x2E,0x72,0x3C,0xD1,0xA4,0x4E,0x29,0x9E,0x8E,0x4A,0x88,0x79,0x7A,0x00,0x04}; -BMD_CONST REFIID IID_IDeckLinkEncoderPacket = /* B693F36C-316E-4AF1-B6C2-F389A4BCA620 */ {0xB6,0x93,0xF3,0x6C,0x31,0x6E,0x4A,0xF1,0xB6,0xC2,0xF3,0x89,0xA4,0xBC,0xA6,0x20}; -BMD_CONST REFIID IID_IDeckLinkEncoderVideoPacket = /* 4E7FD944-E8C7-4EAC-B8C0-7B77F80F5AE0 */ {0x4E,0x7F,0xD9,0x44,0xE8,0xC7,0x4E,0xAC,0xB8,0xC0,0x7B,0x77,0xF8,0x0F,0x5A,0xE0}; -BMD_CONST REFIID IID_IDeckLinkEncoderAudioPacket = /* 49E8EDC8-693B-4E14-8EF6-12C658F5A07A */ {0x49,0xE8,0xED,0xC8,0x69,0x3B,0x4E,0x14,0x8E,0xF6,0x12,0xC6,0x58,0xF5,0xA0,0x7A}; -BMD_CONST REFIID IID_IDeckLinkH265NALPacket = /* 639C8E0B-68D5-4BDE-A6D4-95F3AEAFF2E7 */ {0x63,0x9C,0x8E,0x0B,0x68,0xD5,0x4B,0xDE,0xA6,0xD4,0x95,0xF3,0xAE,0xAF,0xF2,0xE7}; -BMD_CONST REFIID IID_IDeckLinkAudioInputPacket = /* E43D5870-2894-11DE-8C30-0800200C9A66 */ {0xE4,0x3D,0x58,0x70,0x28,0x94,0x11,0xDE,0x8C,0x30,0x08,0x00,0x20,0x0C,0x9A,0x66}; -BMD_CONST REFIID IID_IDeckLinkScreenPreviewCallback = /* B1D3F49A-85FE-4C5D-95C8-0B5D5DCCD438 */ {0xB1,0xD3,0xF4,0x9A,0x85,0xFE,0x4C,0x5D,0x95,0xC8,0x0B,0x5D,0x5D,0xCC,0xD4,0x38}; -BMD_CONST REFIID IID_IDeckLinkCocoaScreenPreviewCallback = /* D174152F-8F96-4C07-83A5-DD5F5AF0A2AA */ {0xD1,0x74,0x15,0x2F,0x8F,0x96,0x4C,0x07,0x83,0xA5,0xDD,0x5F,0x5A,0xF0,0xA2,0xAA}; -BMD_CONST REFIID IID_IDeckLinkGLScreenPreviewHelper = /* 504E2209-CAC7-4C1A-9FB4-C5BB6274D22F */ {0x50,0x4E,0x22,0x09,0xCA,0xC7,0x4C,0x1A,0x9F,0xB4,0xC5,0xBB,0x62,0x74,0xD2,0x2F}; -BMD_CONST REFIID IID_IDeckLinkNotificationCallback = /* B002A1EC-070D-4288-8289-BD5D36E5FF0D */ {0xB0,0x02,0xA1,0xEC,0x07,0x0D,0x42,0x88,0x82,0x89,0xBD,0x5D,0x36,0xE5,0xFF,0x0D}; -BMD_CONST REFIID IID_IDeckLinkNotification = /* 0A1FB207-E215-441B-9B19-6FA1575946C5 */ {0x0A,0x1F,0xB2,0x07,0xE2,0x15,0x44,0x1B,0x9B,0x19,0x6F,0xA1,0x57,0x59,0x46,0xC5}; -BMD_CONST REFIID IID_IDeckLinkAttributes = /* ABC11843-D966-44CB-96E2-A1CB5D3135C4 */ {0xAB,0xC1,0x18,0x43,0xD9,0x66,0x44,0xCB,0x96,0xE2,0xA1,0xCB,0x5D,0x31,0x35,0xC4}; -BMD_CONST REFIID IID_IDeckLinkStatus = /* 5F558200-4028-49BC-BEAC-DB3FA4A96E46 */ {0x5F,0x55,0x82,0x00,0x40,0x28,0x49,0xBC,0xBE,0xAC,0xDB,0x3F,0xA4,0xA9,0x6E,0x46}; -BMD_CONST REFIID IID_IDeckLinkKeyer = /* 89AFCAF5-65F8-421E-98F7-96FE5F5BFBA3 */ {0x89,0xAF,0xCA,0xF5,0x65,0xF8,0x42,0x1E,0x98,0xF7,0x96,0xFE,0x5F,0x5B,0xFB,0xA3}; -BMD_CONST REFIID IID_IDeckLinkVideoConversion = /* 3BBCB8A2-DA2C-42D9-B5D8-88083644E99A */ {0x3B,0xBC,0xB8,0xA2,0xDA,0x2C,0x42,0xD9,0xB5,0xD8,0x88,0x08,0x36,0x44,0xE9,0x9A}; -BMD_CONST REFIID IID_IDeckLinkDeviceNotificationCallback = /* 4997053B-0ADF-4CC8-AC70-7A50C4BE728F */ {0x49,0x97,0x05,0x3B,0x0A,0xDF,0x4C,0xC8,0xAC,0x70,0x7A,0x50,0xC4,0xBE,0x72,0x8F}; -BMD_CONST REFIID IID_IDeckLinkDiscovery = /* CDBF631C-BC76-45FA-B44D-C55059BC6101 */ {0xCD,0xBF,0x63,0x1C,0xBC,0x76,0x45,0xFA,0xB4,0x4D,0xC5,0x50,0x59,0xBC,0x61,0x01}; +BMD_CONST REFIID IID_IDeckLinkVideoOutputCallback = /* 20AA5225-1958-47CB-820B-80A8D521A6EE */ { 0x20,0xAA,0x52,0x25,0x19,0x58,0x47,0xCB,0x82,0x0B,0x80,0xA8,0xD5,0x21,0xA6,0xEE }; +BMD_CONST REFIID IID_IDeckLinkInputCallback = /* C6FCE4C9-C4E4-4047-82FB-5D238232A902 */ { 0xC6,0xFC,0xE4,0xC9,0xC4,0xE4,0x40,0x47,0x82,0xFB,0x5D,0x23,0x82,0x32,0xA9,0x02 }; +BMD_CONST REFIID IID_IDeckLinkEncoderInputCallback = /* ACF13E61-F4A0-4974-A6A7-59AFF6268B31 */ { 0xAC,0xF1,0x3E,0x61,0xF4,0xA0,0x49,0x74,0xA6,0xA7,0x59,0xAF,0xF6,0x26,0x8B,0x31 }; +BMD_CONST REFIID IID_IDeckLinkMemoryAllocator = /* B36EB6E7-9D29-4AA8-92EF-843B87A289E8 */ { 0xB3,0x6E,0xB6,0xE7,0x9D,0x29,0x4A,0xA8,0x92,0xEF,0x84,0x3B,0x87,0xA2,0x89,0xE8 }; +BMD_CONST REFIID IID_IDeckLinkAudioOutputCallback = /* 403C681B-7F46-4A12-B993-2BB127084EE6 */ { 0x40,0x3C,0x68,0x1B,0x7F,0x46,0x4A,0x12,0xB9,0x93,0x2B,0xB1,0x27,0x08,0x4E,0xE6 }; +BMD_CONST REFIID IID_IDeckLinkIterator = /* 50FB36CD-3063-4B73-BDBB-958087F2D8BA */ { 0x50,0xFB,0x36,0xCD,0x30,0x63,0x4B,0x73,0xBD,0xBB,0x95,0x80,0x87,0xF2,0xD8,0xBA }; +BMD_CONST REFIID IID_IDeckLinkAPIInformation = /* 7BEA3C68-730D-4322-AF34-8A7152B532A4 */ { 0x7B,0xEA,0x3C,0x68,0x73,0x0D,0x43,0x22,0xAF,0x34,0x8A,0x71,0x52,0xB5,0x32,0xA4 }; +BMD_CONST REFIID IID_IDeckLinkOutput = /* BE2D9020-461E-442F-84B7-E949CB953B9D */ { 0xBE,0x2D,0x90,0x20,0x46,0x1E,0x44,0x2F,0x84,0xB7,0xE9,0x49,0xCB,0x95,0x3B,0x9D }; +BMD_CONST REFIID IID_IDeckLinkInput = /* C21CDB6E-F414-46E4-A636-80A566E0ED37 */ { 0xC2,0x1C,0xDB,0x6E,0xF4,0x14,0x46,0xE4,0xA6,0x36,0x80,0xA5,0x66,0xE0,0xED,0x37 }; +BMD_CONST REFIID IID_IDeckLinkHDMIInputEDID = /* ABBBACBC-45BC-4665-9D92-ACE6E5A97902 */ { 0xAB,0xBB,0xAC,0xBC,0x45,0xBC,0x46,0x65,0x9D,0x92,0xAC,0xE6,0xE5,0xA9,0x79,0x02 }; +BMD_CONST REFIID IID_IDeckLinkEncoderInput = /* F222551D-13DF-4FD8-B587-9D4F19EC12C9 */ { 0xF2,0x22,0x55,0x1D,0x13,0xDF,0x4F,0xD8,0xB5,0x87,0x9D,0x4F,0x19,0xEC,0x12,0xC9 }; +BMD_CONST REFIID IID_IDeckLinkVideoFrame = /* 3F716FE0-F023-4111-BE5D-EF4414C05B17 */ { 0x3F,0x71,0x6F,0xE0,0xF0,0x23,0x41,0x11,0xBE,0x5D,0xEF,0x44,0x14,0xC0,0x5B,0x17 }; +BMD_CONST REFIID IID_IDeckLinkMutableVideoFrame = /* 69E2639F-40DA-4E19-B6F2-20ACE815C390 */ { 0x69,0xE2,0x63,0x9F,0x40,0xDA,0x4E,0x19,0xB6,0xF2,0x20,0xAC,0xE8,0x15,0xC3,0x90 }; +BMD_CONST REFIID IID_IDeckLinkVideoFrame3DExtensions = /* DA0F7E4A-EDC7-48A8-9CDD-2DB51C729CD7 */ { 0xDA,0x0F,0x7E,0x4A,0xED,0xC7,0x48,0xA8,0x9C,0xDD,0x2D,0xB5,0x1C,0x72,0x9C,0xD7 }; +BMD_CONST REFIID IID_IDeckLinkVideoFrameMetadataExtensions = /* E232A5B7-4DB4-44C9-9152-F47C12E5F051 */ { 0xE2,0x32,0xA5,0xB7,0x4D,0xB4,0x44,0xC9,0x91,0x52,0xF4,0x7C,0x12,0xE5,0xF0,0x51 }; +BMD_CONST REFIID IID_IDeckLinkVideoInputFrame = /* 05CFE374-537C-4094-9A57-680525118F44 */ { 0x05,0xCF,0xE3,0x74,0x53,0x7C,0x40,0x94,0x9A,0x57,0x68,0x05,0x25,0x11,0x8F,0x44 }; +BMD_CONST REFIID IID_IDeckLinkAncillaryPacket = /* CC5BBF7E-029C-4D3B-9158-6000EF5E3670 */ { 0xCC,0x5B,0xBF,0x7E,0x02,0x9C,0x4D,0x3B,0x91,0x58,0x60,0x00,0xEF,0x5E,0x36,0x70 }; +BMD_CONST REFIID IID_IDeckLinkAncillaryPacketIterator = /* 3FC8994B-88FB-4C17-968F-9AAB69D964A7 */ { 0x3F,0xC8,0x99,0x4B,0x88,0xFB,0x4C,0x17,0x96,0x8F,0x9A,0xAB,0x69,0xD9,0x64,0xA7 }; +BMD_CONST REFIID IID_IDeckLinkVideoFrameAncillaryPackets = /* 6C186C0F-459E-41D8-AEE2-4812D81AEE68 */ { 0x6C,0x18,0x6C,0x0F,0x45,0x9E,0x41,0xD8,0xAE,0xE2,0x48,0x12,0xD8,0x1A,0xEE,0x68 }; +BMD_CONST REFIID IID_IDeckLinkVideoFrameAncillary = /* 732E723C-D1A4-4E29-9E8E-4A88797A0004 */ { 0x73,0x2E,0x72,0x3C,0xD1,0xA4,0x4E,0x29,0x9E,0x8E,0x4A,0x88,0x79,0x7A,0x00,0x04 }; +BMD_CONST REFIID IID_IDeckLinkEncoderPacket = /* B693F36C-316E-4AF1-B6C2-F389A4BCA620 */ { 0xB6,0x93,0xF3,0x6C,0x31,0x6E,0x4A,0xF1,0xB6,0xC2,0xF3,0x89,0xA4,0xBC,0xA6,0x20 }; +BMD_CONST REFIID IID_IDeckLinkEncoderVideoPacket = /* 4E7FD944-E8C7-4EAC-B8C0-7B77F80F5AE0 */ { 0x4E,0x7F,0xD9,0x44,0xE8,0xC7,0x4E,0xAC,0xB8,0xC0,0x7B,0x77,0xF8,0x0F,0x5A,0xE0 }; +BMD_CONST REFIID IID_IDeckLinkEncoderAudioPacket = /* 49E8EDC8-693B-4E14-8EF6-12C658F5A07A */ { 0x49,0xE8,0xED,0xC8,0x69,0x3B,0x4E,0x14,0x8E,0xF6,0x12,0xC6,0x58,0xF5,0xA0,0x7A }; +BMD_CONST REFIID IID_IDeckLinkH265NALPacket = /* 639C8E0B-68D5-4BDE-A6D4-95F3AEAFF2E7 */ { 0x63,0x9C,0x8E,0x0B,0x68,0xD5,0x4B,0xDE,0xA6,0xD4,0x95,0xF3,0xAE,0xAF,0xF2,0xE7 }; +BMD_CONST REFIID IID_IDeckLinkAudioInputPacket = /* E43D5870-2894-11DE-8C30-0800200C9A66 */ { 0xE4,0x3D,0x58,0x70,0x28,0x94,0x11,0xDE,0x8C,0x30,0x08,0x00,0x20,0x0C,0x9A,0x66 }; +BMD_CONST REFIID IID_IDeckLinkScreenPreviewCallback = /* B1D3F49A-85FE-4C5D-95C8-0B5D5DCCD438 */ { 0xB1,0xD3,0xF4,0x9A,0x85,0xFE,0x4C,0x5D,0x95,0xC8,0x0B,0x5D,0x5D,0xCC,0xD4,0x38 }; +BMD_CONST REFIID IID_IDeckLinkCocoaScreenPreviewCallback = /* D174152F-8F96-4C07-83A5-DD5F5AF0A2AA */ { 0xD1,0x74,0x15,0x2F,0x8F,0x96,0x4C,0x07,0x83,0xA5,0xDD,0x5F,0x5A,0xF0,0xA2,0xAA }; +BMD_CONST REFIID IID_IDeckLinkGLScreenPreviewHelper = /* 504E2209-CAC7-4C1A-9FB4-C5BB6274D22F */ { 0x50,0x4E,0x22,0x09,0xCA,0xC7,0x4C,0x1A,0x9F,0xB4,0xC5,0xBB,0x62,0x74,0xD2,0x2F }; +BMD_CONST REFIID IID_IDeckLinkNotificationCallback = /* B002A1EC-070D-4288-8289-BD5D36E5FF0D */ { 0xB0,0x02,0xA1,0xEC,0x07,0x0D,0x42,0x88,0x82,0x89,0xBD,0x5D,0x36,0xE5,0xFF,0x0D }; +BMD_CONST REFIID IID_IDeckLinkNotification = /* B85DF4C8-BDF5-47C1-8064-28162EBDD4EB */ { 0xB8,0x5D,0xF4,0xC8,0xBD,0xF5,0x47,0xC1,0x80,0x64,0x28,0x16,0x2E,0xBD,0xD4,0xEB }; +BMD_CONST REFIID IID_IDeckLinkProfileAttributes = /* 17D4BF8E-4911-473A-80A0-731CF6FF345B */ { 0x17,0xD4,0xBF,0x8E,0x49,0x11,0x47,0x3A,0x80,0xA0,0x73,0x1C,0xF6,0xFF,0x34,0x5B }; +BMD_CONST REFIID IID_IDeckLinkProfileIterator = /* 29E5A8C0-8BE4-46EB-93AC-31DAAB5B7BF2 */ { 0x29,0xE5,0xA8,0xC0,0x8B,0xE4,0x46,0xEB,0x93,0xAC,0x31,0xDA,0xAB,0x5B,0x7B,0xF2 }; +BMD_CONST REFIID IID_IDeckLinkProfile = /* 16093466-674A-432B-9DA0-1AC2C5A8241C */ { 0x16,0x09,0x34,0x66,0x67,0x4A,0x43,0x2B,0x9D,0xA0,0x1A,0xC2,0xC5,0xA8,0x24,0x1C }; +BMD_CONST REFIID IID_IDeckLinkProfileCallback = /* A4F9341E-97AA-4E04-8935-15F809898CEA */ { 0xA4,0xF9,0x34,0x1E,0x97,0xAA,0x4E,0x04,0x89,0x35,0x15,0xF8,0x09,0x89,0x8C,0xEA }; +BMD_CONST REFIID IID_IDeckLinkProfileManager = /* 30D41429-3998-4B6D-84F8-78C94A797C6E */ { 0x30,0xD4,0x14,0x29,0x39,0x98,0x4B,0x6D,0x84,0xF8,0x78,0xC9,0x4A,0x79,0x7C,0x6E }; +BMD_CONST REFIID IID_IDeckLinkStatus = /* 5F558200-4028-49BC-BEAC-DB3FA4A96E46 */ { 0x5F,0x55,0x82,0x00,0x40,0x28,0x49,0xBC,0xBE,0xAC,0xDB,0x3F,0xA4,0xA9,0x6E,0x46 }; +BMD_CONST REFIID IID_IDeckLinkKeyer = /* 89AFCAF5-65F8-421E-98F7-96FE5F5BFBA3 */ { 0x89,0xAF,0xCA,0xF5,0x65,0xF8,0x42,0x1E,0x98,0xF7,0x96,0xFE,0x5F,0x5B,0xFB,0xA3 }; +BMD_CONST REFIID IID_IDeckLinkVideoConversion = /* 3BBCB8A2-DA2C-42D9-B5D8-88083644E99A */ { 0x3B,0xBC,0xB8,0xA2,0xDA,0x2C,0x42,0xD9,0xB5,0xD8,0x88,0x08,0x36,0x44,0xE9,0x9A }; +BMD_CONST REFIID IID_IDeckLinkDeviceNotificationCallback = /* 4997053B-0ADF-4CC8-AC70-7A50C4BE728F */ { 0x49,0x97,0x05,0x3B,0x0A,0xDF,0x4C,0xC8,0xAC,0x70,0x7A,0x50,0xC4,0xBE,0x72,0x8F }; +BMD_CONST REFIID IID_IDeckLinkDiscovery = /* CDBF631C-BC76-45FA-B44D-C55059BC6101 */ { 0xCD,0xBF,0x63,0x1C,0xBC,0x76,0x45,0xFA,0xB4,0x4D,0xC5,0x50,0x59,0xBC,0x61,0x01 }; /* Enum BMDVideoOutputFlags - Flags to control the output of ancillary data along with video. */ @@ -107,15 +111,29 @@ enum _BMDVideoOutputFlags { bmdVideoOutputVANC = 1 << 0, bmdVideoOutputVITC = 1 << 1, bmdVideoOutputRP188 = 1 << 2, - bmdVideoOutputDualStream3D = 1 << 4 + bmdVideoOutputDualStream3D = 1 << 4, + bmdVideoOutputSynchronizeToPlaybackGroup = 1 << 6 +}; + +/* Enum BMDSupportedVideoModeFlags - Flags to describe supported video modes */ + +typedef uint32_t BMDSupportedVideoModeFlags; +enum _BMDSupportedVideoModeFlags { + bmdSupportedVideoModeDefault = 0, + bmdSupportedVideoModeKeying = 1 << 0, + bmdSupportedVideoModeDualStream3D = 1 << 1, + bmdSupportedVideoModeSDISingleLink = 1 << 2, + bmdSupportedVideoModeSDIDualLink = 1 << 3, + bmdSupportedVideoModeSDIQuadLink = 1 << 4, + bmdSupportedVideoModeInAnyProfile = 1 << 5 }; /* Enum BMDPacketType - Type of packet */ typedef uint32_t BMDPacketType; enum _BMDPacketType { - bmdPacketTypeStreamInterruptedMarker = 'sint', // A packet of this type marks the time when a video stream was interrupted, for example by a disconnected cable - bmdPacketTypeStreamData = 'sdat' // Regular stream data + bmdPacketTypeStreamInterruptedMarker = /* 'sint' */ 0x73696E74, // A packet of this type marks the time when a video stream was interrupted, for example by a disconnected cable + bmdPacketTypeStreamData = /* 'sdat' */ 0x73646174 // Regular stream data }; /* Enum BMDFrameFlags - Frame flags */ @@ -125,7 +143,6 @@ enum _BMDFrameFlags { bmdFrameFlagDefault = 0, bmdFrameFlagFlipVertical = 1 << 0, bmdFrameContainsHDRMetadata = 1 << 1, - bmdFrameContainsCintelMetadata = 1 << 2, /* Flags that are applicable only to instances of IDeckLinkVideoInputFrame */ @@ -139,7 +156,8 @@ typedef uint32_t BMDVideoInputFlags; enum _BMDVideoInputFlags { bmdVideoInputFlagDefault = 0, bmdVideoInputEnableFormatDetection = 1 << 0, - bmdVideoInputDualStream3D = 1 << 1 + bmdVideoInputDualStream3D = 1 << 1, + bmdVideoInputSynchronizeToCaptureGroup = 1 << 2 }; /* Enum BMDVideoInputFormatChangedEvents - Bitmask passed to the VideoInputFormatChanged notification to identify the properties of the input signal that have changed */ @@ -157,26 +175,29 @@ typedef uint32_t BMDDetectedVideoInputFormatFlags; enum _BMDDetectedVideoInputFormatFlags { bmdDetectedVideoInputYCbCr422 = 1 << 0, bmdDetectedVideoInputRGB444 = 1 << 1, - bmdDetectedVideoInputDualStream3D = 1 << 2 + bmdDetectedVideoInputDualStream3D = 1 << 2, + bmdDetectedVideoInput12BitDepth = 1 << 3, + bmdDetectedVideoInput10BitDepth = 1 << 4, + bmdDetectedVideoInput8BitDepth = 1 << 5 }; /* Enum BMDDeckLinkCapturePassthroughMode - Enumerates whether the video output is electrically connected to the video input or if the clean switching mode is enabled */ typedef uint32_t BMDDeckLinkCapturePassthroughMode; enum _BMDDeckLinkCapturePassthroughMode { - bmdDeckLinkCapturePassthroughModeDisabled = 'pdis', - bmdDeckLinkCapturePassthroughModeDirect = 'pdir', - bmdDeckLinkCapturePassthroughModeCleanSwitch = 'pcln' + bmdDeckLinkCapturePassthroughModeDisabled = /* 'pdis' */ 0x70646973, + bmdDeckLinkCapturePassthroughModeDirect = /* 'pdir' */ 0x70646972, + bmdDeckLinkCapturePassthroughModeCleanSwitch = /* 'pcln' */ 0x70636C6E }; /* Enum BMDOutputFrameCompletionResult - Frame Completion Callback */ typedef uint32_t BMDOutputFrameCompletionResult; enum _BMDOutputFrameCompletionResult { - bmdOutputFrameCompleted, - bmdOutputFrameDisplayedLate, - bmdOutputFrameDropped, - bmdOutputFrameFlushed + bmdOutputFrameCompleted, + bmdOutputFrameDisplayedLate, + bmdOutputFrameDropped, + bmdOutputFrameFlushed }; /* Enum BMDReferenceStatus - GenLock input status */ @@ -191,7 +212,7 @@ enum _BMDReferenceStatus { typedef uint32_t BMDAudioFormat; enum _BMDAudioFormat { - bmdAudioFormatPCM = 'lpcm' // Linear signed PCM samples + bmdAudioFormatPCM = /* 'lpcm' */ 0x6C70636D // Linear signed PCM samples }; /* Enum BMDAudioSampleRate - Audio sample rates supported for output/input */ @@ -213,40 +234,32 @@ enum _BMDAudioSampleType { typedef uint32_t BMDAudioOutputStreamType; enum _BMDAudioOutputStreamType { - bmdAudioOutputStreamContinuous, - bmdAudioOutputStreamContinuousDontResample, - bmdAudioOutputStreamTimestamped -}; - -/* Enum BMDDisplayModeSupport - Output mode supported flags */ - -typedef uint32_t BMDDisplayModeSupport; -enum _BMDDisplayModeSupport { - bmdDisplayModeNotSupported = 0, - bmdDisplayModeSupported, - bmdDisplayModeSupportedWithConversion + bmdAudioOutputStreamContinuous, + bmdAudioOutputStreamContinuousDontResample, + bmdAudioOutputStreamTimestamped }; /* Enum BMDAncillaryPacketFormat - Ancillary packet format */ typedef uint32_t BMDAncillaryPacketFormat; enum _BMDAncillaryPacketFormat { - bmdAncillaryPacketFormatUInt8 = 'ui08', - bmdAncillaryPacketFormatUInt16 = 'ui16', - bmdAncillaryPacketFormatYCbCr10 = 'v210' + bmdAncillaryPacketFormatUInt8 = /* 'ui08' */ 0x75693038, + bmdAncillaryPacketFormatUInt16 = /* 'ui16' */ 0x75693136, + bmdAncillaryPacketFormatYCbCr10 = /* 'v210' */ 0x76323130 }; /* Enum BMDTimecodeFormat - Timecode formats for frame metadata */ typedef uint32_t BMDTimecodeFormat; enum _BMDTimecodeFormat { - bmdTimecodeRP188VITC1 = 'rpv1', // RP188 timecode where DBB1 equals VITC1 (line 9) - bmdTimecodeRP188VITC2 = 'rp12', // RP188 timecode where DBB1 equals VITC2 (line 9 for progressive or line 571 for interlaced/PsF) - bmdTimecodeRP188LTC = 'rplt', // RP188 timecode where DBB1 equals LTC (line 10) - bmdTimecodeRP188Any = 'rp18', // For capture: return the first valid timecode in {VITC1, LTC ,VITC2} - For playback: set the timecode as VITC1 - bmdTimecodeVITC = 'vitc', - bmdTimecodeVITCField2 = 'vit2', - bmdTimecodeSerial = 'seri' + bmdTimecodeRP188VITC1 = /* 'rpv1' */ 0x72707631, // RP188 timecode where DBB1 equals VITC1 (line 9) + bmdTimecodeRP188VITC2 = /* 'rp12' */ 0x72703132, // RP188 timecode where DBB1 equals VITC2 (line 9 for progressive or line 571 for interlaced/PsF) + bmdTimecodeRP188LTC = /* 'rplt' */ 0x72706C74, // RP188 timecode where DBB1 equals LTC (line 10) + bmdTimecodeRP188HighFrameRate = /* 'rphr' */ 0x72706872, // RP188 timecode where DBB1 is an HFRTC (SMPTE ST 12-3), the only timecode allowing the frame value to go above 30 + bmdTimecodeRP188Any = /* 'rp18' */ 0x72703138, // Convenience for capture, returning the first valid timecode in {HFRTC (if supported), VITC1, LTC, VITC2} + bmdTimecodeVITC = /* 'vitc' */ 0x76697463, + bmdTimecodeVITCField2 = /* 'vit2' */ 0x76697432, + bmdTimecodeSerial = /* 'seri' */ 0x73657269 }; /* Enum BMDAnalogVideoFlags - Analog video display flags */ @@ -261,190 +274,183 @@ enum _BMDAnalogVideoFlags { typedef uint32_t BMDAudioOutputAnalogAESSwitch; enum _BMDAudioOutputAnalogAESSwitch { - bmdAudioOutputSwitchAESEBU = 'aes ', - bmdAudioOutputSwitchAnalog = 'anlg' + bmdAudioOutputSwitchAESEBU = /* 'aes ' */ 0x61657320, + bmdAudioOutputSwitchAnalog = /* 'anlg' */ 0x616E6C67 }; /* Enum BMDVideoOutputConversionMode - Video/audio conversion mode */ typedef uint32_t BMDVideoOutputConversionMode; enum _BMDVideoOutputConversionMode { - bmdNoVideoOutputConversion = 'none', - bmdVideoOutputLetterboxDownconversion = 'ltbx', - bmdVideoOutputAnamorphicDownconversion = 'amph', - bmdVideoOutputHD720toHD1080Conversion = '720c', - bmdVideoOutputHardwareLetterboxDownconversion = 'HWlb', - bmdVideoOutputHardwareAnamorphicDownconversion = 'HWam', - bmdVideoOutputHardwareCenterCutDownconversion = 'HWcc', - bmdVideoOutputHardware720p1080pCrossconversion = 'xcap', - bmdVideoOutputHardwareAnamorphic720pUpconversion = 'ua7p', - bmdVideoOutputHardwareAnamorphic1080iUpconversion = 'ua1i', - bmdVideoOutputHardwareAnamorphic149To720pUpconversion = 'u47p', - bmdVideoOutputHardwareAnamorphic149To1080iUpconversion = 'u41i', - bmdVideoOutputHardwarePillarbox720pUpconversion = 'up7p', - bmdVideoOutputHardwarePillarbox1080iUpconversion = 'up1i' + bmdNoVideoOutputConversion = /* 'none' */ 0x6E6F6E65, + bmdVideoOutputLetterboxDownconversion = /* 'ltbx' */ 0x6C746278, + bmdVideoOutputAnamorphicDownconversion = /* 'amph' */ 0x616D7068, + bmdVideoOutputHD720toHD1080Conversion = /* '720c' */ 0x37323063, + bmdVideoOutputHardwareLetterboxDownconversion = /* 'HWlb' */ 0x48576C62, + bmdVideoOutputHardwareAnamorphicDownconversion = /* 'HWam' */ 0x4857616D, + bmdVideoOutputHardwareCenterCutDownconversion = /* 'HWcc' */ 0x48576363, + bmdVideoOutputHardware720p1080pCrossconversion = /* 'xcap' */ 0x78636170, + bmdVideoOutputHardwareAnamorphic720pUpconversion = /* 'ua7p' */ 0x75613770, + bmdVideoOutputHardwareAnamorphic1080iUpconversion = /* 'ua1i' */ 0x75613169, + bmdVideoOutputHardwareAnamorphic149To720pUpconversion = /* 'u47p' */ 0x75343770, + bmdVideoOutputHardwareAnamorphic149To1080iUpconversion = /* 'u41i' */ 0x75343169, + bmdVideoOutputHardwarePillarbox720pUpconversion = /* 'up7p' */ 0x75703770, + bmdVideoOutputHardwarePillarbox1080iUpconversion = /* 'up1i' */ 0x75703169 }; /* Enum BMDVideoInputConversionMode - Video input conversion mode */ typedef uint32_t BMDVideoInputConversionMode; enum _BMDVideoInputConversionMode { - bmdNoVideoInputConversion = 'none', - bmdVideoInputLetterboxDownconversionFromHD1080 = '10lb', - bmdVideoInputAnamorphicDownconversionFromHD1080 = '10am', - bmdVideoInputLetterboxDownconversionFromHD720 = '72lb', - bmdVideoInputAnamorphicDownconversionFromHD720 = '72am', - bmdVideoInputLetterboxUpconversion = 'lbup', - bmdVideoInputAnamorphicUpconversion = 'amup' + bmdNoVideoInputConversion = /* 'none' */ 0x6E6F6E65, + bmdVideoInputLetterboxDownconversionFromHD1080 = /* '10lb' */ 0x31306C62, + bmdVideoInputAnamorphicDownconversionFromHD1080 = /* '10am' */ 0x3130616D, + bmdVideoInputLetterboxDownconversionFromHD720 = /* '72lb' */ 0x37326C62, + bmdVideoInputAnamorphicDownconversionFromHD720 = /* '72am' */ 0x3732616D, + bmdVideoInputLetterboxUpconversion = /* 'lbup' */ 0x6C627570, + bmdVideoInputAnamorphicUpconversion = /* 'amup' */ 0x616D7570 }; /* Enum BMDVideo3DPackingFormat - Video 3D packing format */ typedef uint32_t BMDVideo3DPackingFormat; enum _BMDVideo3DPackingFormat { - bmdVideo3DPackingSidebySideHalf = 'sbsh', - bmdVideo3DPackingLinebyLine = 'lbyl', - bmdVideo3DPackingTopAndBottom = 'tabo', - bmdVideo3DPackingFramePacking = 'frpk', - bmdVideo3DPackingLeftOnly = 'left', - bmdVideo3DPackingRightOnly = 'righ' + bmdVideo3DPackingSidebySideHalf = /* 'sbsh' */ 0x73627368, + bmdVideo3DPackingLinebyLine = /* 'lbyl' */ 0x6C62796C, + bmdVideo3DPackingTopAndBottom = /* 'tabo' */ 0x7461626F, + bmdVideo3DPackingFramePacking = /* 'frpk' */ 0x6672706B, + bmdVideo3DPackingLeftOnly = /* 'left' */ 0x6C656674, + bmdVideo3DPackingRightOnly = /* 'righ' */ 0x72696768 }; /* Enum BMDIdleVideoOutputOperation - Video output operation when not playing video */ typedef uint32_t BMDIdleVideoOutputOperation; enum _BMDIdleVideoOutputOperation { - bmdIdleVideoOutputBlack = 'blac', - bmdIdleVideoOutputLastFrame = 'lafa' + bmdIdleVideoOutputBlack = /* 'blac' */ 0x626C6163, + bmdIdleVideoOutputLastFrame = /* 'lafa' */ 0x6C616661 }; /* Enum BMDVideoEncoderFrameCodingMode - Video frame coding mode */ typedef uint32_t BMDVideoEncoderFrameCodingMode; enum _BMDVideoEncoderFrameCodingMode { - bmdVideoEncoderFrameCodingModeInter = 'inte', - bmdVideoEncoderFrameCodingModeIntra = 'intr' + bmdVideoEncoderFrameCodingModeInter = /* 'inte' */ 0x696E7465, + bmdVideoEncoderFrameCodingModeIntra = /* 'intr' */ 0x696E7472 }; /* Enum BMDDNxHRLevel - DNxHR Levels */ typedef uint32_t BMDDNxHRLevel; enum _BMDDNxHRLevel { - bmdDNxHRLevelSQ = 'dnsq', - bmdDNxHRLevelLB = 'dnlb', - bmdDNxHRLevelHQ = 'dnhq', - bmdDNxHRLevelHQX = 'dhqx', - bmdDNxHRLevel444 = 'd444' + bmdDNxHRLevelSQ = /* 'dnsq' */ 0x646E7371, + bmdDNxHRLevelLB = /* 'dnlb' */ 0x646E6C62, + bmdDNxHRLevelHQ = /* 'dnhq' */ 0x646E6871, + bmdDNxHRLevelHQX = /* 'dhqx' */ 0x64687178, + bmdDNxHRLevel444 = /* 'd444' */ 0x64343434 }; /* Enum BMDLinkConfiguration - Video link configuration */ typedef uint32_t BMDLinkConfiguration; enum _BMDLinkConfiguration { - bmdLinkConfigurationSingleLink = 'lcsl', - bmdLinkConfigurationDualLink = 'lcdl', - bmdLinkConfigurationQuadLink = 'lcql' + bmdLinkConfigurationSingleLink = /* 'lcsl' */ 0x6C63736C, + bmdLinkConfigurationDualLink = /* 'lcdl' */ 0x6C63646C, + bmdLinkConfigurationQuadLink = /* 'lcql' */ 0x6C63716C }; /* Enum BMDDeviceInterface - Device interface type */ typedef uint32_t BMDDeviceInterface; enum _BMDDeviceInterface { - bmdDeviceInterfacePCI = 'pci ', - bmdDeviceInterfaceUSB = 'usb ', - bmdDeviceInterfaceThunderbolt = 'thun' + bmdDeviceInterfacePCI = /* 'pci ' */ 0x70636920, + bmdDeviceInterfaceUSB = /* 'usb ' */ 0x75736220, + bmdDeviceInterfaceThunderbolt = /* 'thun' */ 0x7468756E }; /* Enum BMDColorspace - Colorspace */ typedef uint32_t BMDColorspace; enum _BMDColorspace { - bmdColorspaceRec601 = 'r601', - bmdColorspaceRec709 = 'r709', - bmdColorspaceRec2020 = '2020' + bmdColorspaceRec601 = /* 'r601' */ 0x72363031, + bmdColorspaceRec709 = /* 'r709' */ 0x72373039, + bmdColorspaceRec2020 = /* '2020' */ 0x32303230 }; /* Enum BMDDynamicRange - SDR or HDR */ typedef uint32_t BMDDynamicRange; enum _BMDDynamicRange { - bmdDynamicRangeSDR = 0, - bmdDynamicRangeHDRStaticPQ = 1 << 29, // SMPTE ST 2084 - bmdDynamicRangeHDRStaticHLG = 1 << 30 // ITU-R BT.2100-0 + bmdDynamicRangeSDR = 0, // Standard Dynamic Range in accordance with SMPTE ST 2036-1 + bmdDynamicRangeHDRStaticPQ = 1 << 29, // High Dynamic Range PQ in accordance with SMPTE ST 2084 + bmdDynamicRangeHDRStaticHLG = 1 << 30 // High Dynamic Range HLG in accordance with ITU-R BT.2100-0 }; /* Enum BMDDeckLinkHDMIInputEDIDID - DeckLink HDMI Input EDID ID */ typedef uint32_t BMDDeckLinkHDMIInputEDIDID; enum _BMDDeckLinkHDMIInputEDIDID { - bmdDeckLinkHDMIInputEDIDDynamicRange = 'HIDy' // Parameter is of type BMDDynamicRange. Default is (bmdDynamicRangeSDR|bmdDynamicRangeHDRStaticPQ) + + /* Integers */ + + bmdDeckLinkHDMIInputEDIDDynamicRange = /* 'HIDy' */ 0x48494479 // Parameter is of type BMDDynamicRange. Default is (bmdDynamicRangeSDR|bmdDynamicRangeHDRStaticPQ) }; /* Enum BMDDeckLinkFrameMetadataID - DeckLink Frame Metadata ID */ typedef uint32_t BMDDeckLinkFrameMetadataID; enum _BMDDeckLinkFrameMetadataID { - bmdDeckLinkFrameMetadataColorspace = 'cspc', // Colorspace of video frame (see BMDColorspace) - bmdDeckLinkFrameMetadataHDRElectroOpticalTransferFunc = 'eotf', // EOTF in range 0-7 as per CEA 861.3 - bmdDeckLinkFrameMetadataCintelFilmType = 'cfty', // Current film type - bmdDeckLinkFrameMetadataCintelFilmGauge = 'cfga', // Current film gauge - bmdDeckLinkFrameMetadataCintelOffsetDetectedHorizontal = 'odfh', // Horizontal offset (pixels) detected in image - bmdDeckLinkFrameMetadataCintelOffsetDetectedVertical = 'odfv', // Vertical offset (pixels) detected in image - bmdDeckLinkFrameMetadataCintelKeykodeLow = 'ckkl', // Raw keykode value - low 64 bits - bmdDeckLinkFrameMetadataCintelKeykodeHigh = 'ckkh', // Raw keykode value - high 64 bits - bmdDeckLinkFrameMetadataCintelTile1Size = 'ct1s', // Size in bytes of compressed raw tile 1 - bmdDeckLinkFrameMetadataCintelTile2Size = 'ct2s', // Size in bytes of compressed raw tile 2 - bmdDeckLinkFrameMetadataCintelTile3Size = 'ct3s', // Size in bytes of compressed raw tile 3 - bmdDeckLinkFrameMetadataCintelTile4Size = 'ct4s', // Size in bytes of compressed raw tile 4 - bmdDeckLinkFrameMetadataCintelImageWidth = 'IWPx', // Width in pixels of image - bmdDeckLinkFrameMetadataCintelImageHeight = 'IHPx', // Height in pixels of image - bmdDeckLinkFrameMetadataCintelLinearMaskingRedInRed = 'mrir', // Red in red linear masking parameter - bmdDeckLinkFrameMetadataCintelLinearMaskingGreenInRed = 'mgir', // Green in red linear masking parameter - bmdDeckLinkFrameMetadataCintelLinearMaskingBlueInRed = 'mbir', // Blue in red linear masking parameter - bmdDeckLinkFrameMetadataCintelLinearMaskingRedInGreen = 'mrig', // Red in green linear masking parameter - bmdDeckLinkFrameMetadataCintelLinearMaskingGreenInGreen = 'mgig', // Green in green linear masking parameter - bmdDeckLinkFrameMetadataCintelLinearMaskingBlueInGreen = 'mbig', // Blue in green linear masking parameter - bmdDeckLinkFrameMetadataCintelLinearMaskingRedInBlue = 'mrib', // Red in blue linear masking parameter - bmdDeckLinkFrameMetadataCintelLinearMaskingGreenInBlue = 'mgib', // Green in blue linear masking parameter - bmdDeckLinkFrameMetadataCintelLinearMaskingBlueInBlue = 'mbib', // Blue in blue linear masking parameter - bmdDeckLinkFrameMetadataCintelLogMaskingRedInRed = 'mlrr', // Red in red log masking parameter - bmdDeckLinkFrameMetadataCintelLogMaskingGreenInRed = 'mlgr', // Green in red log masking parameter - bmdDeckLinkFrameMetadataCintelLogMaskingBlueInRed = 'mlbr', // Blue in red log masking parameter - bmdDeckLinkFrameMetadataCintelLogMaskingRedInGreen = 'mlrg', // Red in green log masking parameter - bmdDeckLinkFrameMetadataCintelLogMaskingGreenInGreen = 'mlgg', // Green in green log masking parameter - bmdDeckLinkFrameMetadataCintelLogMaskingBlueInGreen = 'mlbg', // Blue in green log masking parameter - bmdDeckLinkFrameMetadataCintelLogMaskingRedInBlue = 'mlrb', // Red in blue log masking parameter - bmdDeckLinkFrameMetadataCintelLogMaskingGreenInBlue = 'mlgb', // Green in blue log masking parameter - bmdDeckLinkFrameMetadataCintelLogMaskingBlueInBlue = 'mlbb', // Blue in blue log masking parameter - bmdDeckLinkFrameMetadataCintelFilmFrameRate = 'cffr', // Film frame rate - bmdDeckLinkFrameMetadataHDRDisplayPrimariesRedX = 'hdrx', // Red display primaries in range 0.0 - 1.0 - bmdDeckLinkFrameMetadataHDRDisplayPrimariesRedY = 'hdry', // Red display primaries in range 0.0 - 1.0 - bmdDeckLinkFrameMetadataHDRDisplayPrimariesGreenX = 'hdgx', // Green display primaries in range 0.0 - 1.0 - bmdDeckLinkFrameMetadataHDRDisplayPrimariesGreenY = 'hdgy', // Green display primaries in range 0.0 - 1.0 - bmdDeckLinkFrameMetadataHDRDisplayPrimariesBlueX = 'hdbx', // Blue display primaries in range 0.0 - 1.0 - bmdDeckLinkFrameMetadataHDRDisplayPrimariesBlueY = 'hdby', // Blue display primaries in range 0.0 - 1.0 - bmdDeckLinkFrameMetadataHDRWhitePointX = 'hdwx', // White point in range 0.0 - 1.0 - bmdDeckLinkFrameMetadataHDRWhitePointY = 'hdwy', // White point in range 0.0 - 1.0 - bmdDeckLinkFrameMetadataHDRMaxDisplayMasteringLuminance = 'hdml', // Max display mastering luminance in range 1 cd/m2 - 65535 cd/m2 - bmdDeckLinkFrameMetadataHDRMinDisplayMasteringLuminance = 'hmil', // Min display mastering luminance in range 0.0001 cd/m2 - 6.5535 cd/m2 - bmdDeckLinkFrameMetadataHDRMaximumContentLightLevel = 'mcll', // Maximum Content Light Level in range 1 cd/m2 - 65535 cd/m2 - bmdDeckLinkFrameMetadataHDRMaximumFrameAverageLightLevel = 'fall', // Maximum Frame Average Light Level in range 1 cd/m2 - 65535 cd/m2 - bmdDeckLinkFrameMetadataCintelOffsetToApplyHorizontal = 'otah', // Horizontal offset (pixels) to be applied to image - bmdDeckLinkFrameMetadataCintelOffsetToApplyVertical = 'otav', // Vertical offset (pixels) to be applied to image - bmdDeckLinkFrameMetadataCintelGainRed = 'LfRd', // Red gain parameter to apply after log - bmdDeckLinkFrameMetadataCintelGainGreen = 'LfGr', // Green gain parameter to apply after log - bmdDeckLinkFrameMetadataCintelGainBlue = 'LfBl', // Blue gain parameter to apply after log - bmdDeckLinkFrameMetadataCintelLiftRed = 'GnRd', // Red lift parameter to apply after log and gain - bmdDeckLinkFrameMetadataCintelLiftGreen = 'GnGr', // Green lift parameter to apply after log and gain - bmdDeckLinkFrameMetadataCintelLiftBlue = 'GnBl' // Blue lift parameter to apply after log and gain + + /* Colorspace Metadata - Integers */ + + bmdDeckLinkFrameMetadataColorspace = /* 'cspc' */ 0x63737063, // Colorspace of video frame (see BMDColorspace) + + /* HDR Metadata - Integers */ + + bmdDeckLinkFrameMetadataHDRElectroOpticalTransferFunc = /* 'eotf' */ 0x656F7466, // EOTF in range 0-7 as per CEA 861.3 + + /* HDR Metadata - Floats */ + + bmdDeckLinkFrameMetadataHDRDisplayPrimariesRedX = /* 'hdrx' */ 0x68647278, // Red display primaries in range 0.0 - 1.0 + bmdDeckLinkFrameMetadataHDRDisplayPrimariesRedY = /* 'hdry' */ 0x68647279, // Red display primaries in range 0.0 - 1.0 + bmdDeckLinkFrameMetadataHDRDisplayPrimariesGreenX = /* 'hdgx' */ 0x68646778, // Green display primaries in range 0.0 - 1.0 + bmdDeckLinkFrameMetadataHDRDisplayPrimariesGreenY = /* 'hdgy' */ 0x68646779, // Green display primaries in range 0.0 - 1.0 + bmdDeckLinkFrameMetadataHDRDisplayPrimariesBlueX = /* 'hdbx' */ 0x68646278, // Blue display primaries in range 0.0 - 1.0 + bmdDeckLinkFrameMetadataHDRDisplayPrimariesBlueY = /* 'hdby' */ 0x68646279, // Blue display primaries in range 0.0 - 1.0 + bmdDeckLinkFrameMetadataHDRWhitePointX = /* 'hdwx' */ 0x68647778, // White point in range 0.0 - 1.0 + bmdDeckLinkFrameMetadataHDRWhitePointY = /* 'hdwy' */ 0x68647779, // White point in range 0.0 - 1.0 + bmdDeckLinkFrameMetadataHDRMaxDisplayMasteringLuminance = /* 'hdml' */ 0x68646D6C, // Max display mastering luminance in range 1 cd/m2 - 65535 cd/m2 + bmdDeckLinkFrameMetadataHDRMinDisplayMasteringLuminance = /* 'hmil' */ 0x686D696C, // Min display mastering luminance in range 0.0001 cd/m2 - 6.5535 cd/m2 + bmdDeckLinkFrameMetadataHDRMaximumContentLightLevel = /* 'mcll' */ 0x6D636C6C, // Maximum Content Light Level in range 1 cd/m2 - 65535 cd/m2 + bmdDeckLinkFrameMetadataHDRMaximumFrameAverageLightLevel = /* 'fall' */ 0x66616C6C // Maximum Frame Average Light Level in range 1 cd/m2 - 65535 cd/m2 }; -/* Enum BMDDuplexMode - Duplex for configurable ports */ +/* Enum BMDProfileID - Identifies a profile */ -typedef uint32_t BMDDuplexMode; -enum _BMDDuplexMode { - bmdDuplexModeFull = 'fdup', - bmdDuplexModeHalf = 'hdup' +typedef uint32_t BMDProfileID; +enum _BMDProfileID { + bmdProfileOneSubDeviceFullDuplex = /* '1dfd' */ 0x31646664, + bmdProfileOneSubDeviceHalfDuplex = /* '1dhd' */ 0x31646864, + bmdProfileTwoSubDevicesFullDuplex = /* '2dfd' */ 0x32646664, + bmdProfileTwoSubDevicesHalfDuplex = /* '2dhd' */ 0x32646864, + bmdProfileFourSubDevicesHalfDuplex = /* '4dhd' */ 0x34646864 +}; + +/* Enum BMDHDMITimecodePacking - Packing form of timecode on HDMI */ + +typedef uint32_t BMDHDMITimecodePacking; +enum _BMDHDMITimecodePacking { + bmdHDMITimecodePackingIEEEOUI000085 = 0x00008500, + bmdHDMITimecodePackingIEEEOUI080046 = 0x08004601, + bmdHDMITimecodePackingIEEEOUI5CF9F0 = 0x5CF9F003 +}; + +/* Enum BMDInternalKeyingAncillaryDataSource - Source for VANC and timecode data when performing internal keying */ + +typedef uint32_t BMDInternalKeyingAncillaryDataSource; +enum _BMDInternalKeyingAncillaryDataSource { + bmdInternalKeyingUsesAncillaryDataFromInputSignal = /* 'ikai' */ 0x696B6169, + bmdInternalKeyingUsesAncillaryDataFromKeyFrame = /* 'ikak' */ 0x696B616B }; /* Enum BMDDeckLinkAttributeID - DeckLink Attribute ID */ @@ -454,74 +460,83 @@ enum _BMDDeckLinkAttributeID { /* Flags */ - BMDDeckLinkSupportsInternalKeying = 'keyi', - BMDDeckLinkSupportsExternalKeying = 'keye', - BMDDeckLinkSupportsHDKeying = 'keyh', - BMDDeckLinkSupportsInputFormatDetection = 'infd', - BMDDeckLinkHasReferenceInput = 'hrin', - BMDDeckLinkHasSerialPort = 'hspt', - BMDDeckLinkHasAnalogVideoOutputGain = 'avog', - BMDDeckLinkCanOnlyAdjustOverallVideoOutputGain = 'ovog', - BMDDeckLinkHasVideoInputAntiAliasingFilter = 'aafl', - BMDDeckLinkHasBypass = 'byps', - BMDDeckLinkSupportsClockTimingAdjustment = 'ctad', - BMDDeckLinkSupportsFullDuplex = 'fdup', - BMDDeckLinkSupportsFullFrameReferenceInputTimingOffset = 'frin', - BMDDeckLinkSupportsSMPTELevelAOutput = 'lvla', - BMDDeckLinkSupportsDualLinkSDI = 'sdls', - BMDDeckLinkSupportsQuadLinkSDI = 'sqls', - BMDDeckLinkSupportsIdleOutput = 'idou', - BMDDeckLinkHasLTCTimecodeInput = 'hltc', - BMDDeckLinkSupportsDuplexModeConfiguration = 'dupx', - BMDDeckLinkSupportsHDRMetadata = 'hdrm', - BMDDeckLinkSupportsColorspaceMetadata = 'cmet', + BMDDeckLinkSupportsInternalKeying = /* 'keyi' */ 0x6B657969, + BMDDeckLinkSupportsExternalKeying = /* 'keye' */ 0x6B657965, + BMDDeckLinkSupportsInputFormatDetection = /* 'infd' */ 0x696E6664, + BMDDeckLinkHasReferenceInput = /* 'hrin' */ 0x6872696E, + BMDDeckLinkHasSerialPort = /* 'hspt' */ 0x68737074, + BMDDeckLinkHasAnalogVideoOutputGain = /* 'avog' */ 0x61766F67, + BMDDeckLinkCanOnlyAdjustOverallVideoOutputGain = /* 'ovog' */ 0x6F766F67, + BMDDeckLinkHasVideoInputAntiAliasingFilter = /* 'aafl' */ 0x6161666C, + BMDDeckLinkHasBypass = /* 'byps' */ 0x62797073, + BMDDeckLinkSupportsClockTimingAdjustment = /* 'ctad' */ 0x63746164, + BMDDeckLinkSupportsFullFrameReferenceInputTimingOffset = /* 'frin' */ 0x6672696E, + BMDDeckLinkSupportsSMPTELevelAOutput = /* 'lvla' */ 0x6C766C61, + BMDDeckLinkSupportsAutoSwitchingPPsFOnInput = /* 'apsf' */ 0x61707366, + BMDDeckLinkSupportsDualLinkSDI = /* 'sdls' */ 0x73646C73, + BMDDeckLinkSupportsQuadLinkSDI = /* 'sqls' */ 0x73716C73, + BMDDeckLinkSupportsIdleOutput = /* 'idou' */ 0x69646F75, + BMDDeckLinkVANCRequires10BitYUVVideoFrames = /* 'vioY' */ 0x76696F59, // Legacy product requires v210 active picture for IDeckLinkVideoFrameAncillaryPackets or 10-bit VANC + BMDDeckLinkHasLTCTimecodeInput = /* 'hltc' */ 0x686C7463, + BMDDeckLinkSupportsHDRMetadata = /* 'hdrm' */ 0x6864726D, + BMDDeckLinkSupportsColorspaceMetadata = /* 'cmet' */ 0x636D6574, + BMDDeckLinkSupportsHDMITimecode = /* 'htim' */ 0x6874696D, + BMDDeckLinkSupportsHighFrameRateTimecode = /* 'HFRT' */ 0x48465254, + BMDDeckLinkSupportsSynchronizeToCaptureGroup = /* 'stcg' */ 0x73746367, + BMDDeckLinkSupportsSynchronizeToPlaybackGroup = /* 'stpg' */ 0x73747067, /* Integers */ - BMDDeckLinkMaximumAudioChannels = 'mach', - BMDDeckLinkMaximumAnalogAudioInputChannels = 'iach', - BMDDeckLinkMaximumAnalogAudioOutputChannels = 'aach', - BMDDeckLinkNumberOfSubDevices = 'nsbd', - BMDDeckLinkSubDeviceIndex = 'subi', - BMDDeckLinkPersistentID = 'peid', - BMDDeckLinkDeviceGroupID = 'dgid', - BMDDeckLinkTopologicalID = 'toid', - BMDDeckLinkVideoOutputConnections = 'vocn', // Returns a BMDVideoConnection bit field - BMDDeckLinkVideoInputConnections = 'vicn', // Returns a BMDVideoConnection bit field - BMDDeckLinkAudioOutputConnections = 'aocn', // Returns a BMDAudioConnection bit field - BMDDeckLinkAudioInputConnections = 'aicn', // Returns a BMDAudioConnection bit field - BMDDeckLinkVideoIOSupport = 'vios', // Returns a BMDVideoIOSupport bit field - BMDDeckLinkDeckControlConnections = 'dccn', // Returns a BMDDeckControlConnection bit field - BMDDeckLinkDeviceInterface = 'dbus', // Returns a BMDDeviceInterface - BMDDeckLinkAudioInputRCAChannelCount = 'airc', - BMDDeckLinkAudioInputXLRChannelCount = 'aixc', - BMDDeckLinkAudioOutputRCAChannelCount = 'aorc', - BMDDeckLinkAudioOutputXLRChannelCount = 'aoxc', - BMDDeckLinkPairedDevicePersistentID = 'ppid', + BMDDeckLinkMaximumAudioChannels = /* 'mach' */ 0x6D616368, + BMDDeckLinkMaximumAnalogAudioInputChannels = /* 'iach' */ 0x69616368, + BMDDeckLinkMaximumAnalogAudioOutputChannels = /* 'aach' */ 0x61616368, + BMDDeckLinkNumberOfSubDevices = /* 'nsbd' */ 0x6E736264, + BMDDeckLinkSubDeviceIndex = /* 'subi' */ 0x73756269, + BMDDeckLinkPersistentID = /* 'peid' */ 0x70656964, + BMDDeckLinkDeviceGroupID = /* 'dgid' */ 0x64676964, + BMDDeckLinkTopologicalID = /* 'toid' */ 0x746F6964, + BMDDeckLinkVideoOutputConnections = /* 'vocn' */ 0x766F636E, // Returns a BMDVideoConnection bit field + BMDDeckLinkVideoInputConnections = /* 'vicn' */ 0x7669636E, // Returns a BMDVideoConnection bit field + BMDDeckLinkAudioOutputConnections = /* 'aocn' */ 0x616F636E, // Returns a BMDAudioConnection bit field + BMDDeckLinkAudioInputConnections = /* 'aicn' */ 0x6169636E, // Returns a BMDAudioConnection bit field + BMDDeckLinkVideoIOSupport = /* 'vios' */ 0x76696F73, // Returns a BMDVideoIOSupport bit field + BMDDeckLinkDeckControlConnections = /* 'dccn' */ 0x6463636E, // Returns a BMDDeckControlConnection bit field + BMDDeckLinkDeviceInterface = /* 'dbus' */ 0x64627573, // Returns a BMDDeviceInterface + BMDDeckLinkAudioInputRCAChannelCount = /* 'airc' */ 0x61697263, + BMDDeckLinkAudioInputXLRChannelCount = /* 'aixc' */ 0x61697863, + BMDDeckLinkAudioOutputRCAChannelCount = /* 'aorc' */ 0x616F7263, + BMDDeckLinkAudioOutputXLRChannelCount = /* 'aoxc' */ 0x616F7863, + BMDDeckLinkProfileID = /* 'prid' */ 0x70726964, // Returns a BMDProfileID + BMDDeckLinkDuplex = /* 'dupx' */ 0x64757078, + BMDDeckLinkMinimumPrerollFrames = /* 'mprf' */ 0x6D707266, + BMDDeckLinkSupportedDynamicRange = /* 'sudr' */ 0x73756472, /* Floats */ - BMDDeckLinkVideoInputGainMinimum = 'vigm', - BMDDeckLinkVideoInputGainMaximum = 'vigx', - BMDDeckLinkVideoOutputGainMinimum = 'vogm', - BMDDeckLinkVideoOutputGainMaximum = 'vogx', - BMDDeckLinkMicrophoneInputGainMinimum = 'migm', - BMDDeckLinkMicrophoneInputGainMaximum = 'migx', + BMDDeckLinkVideoInputGainMinimum = /* 'vigm' */ 0x7669676D, + BMDDeckLinkVideoInputGainMaximum = /* 'vigx' */ 0x76696778, + BMDDeckLinkVideoOutputGainMinimum = /* 'vogm' */ 0x766F676D, + BMDDeckLinkVideoOutputGainMaximum = /* 'vogx' */ 0x766F6778, + BMDDeckLinkMicrophoneInputGainMinimum = /* 'migm' */ 0x6D69676D, + BMDDeckLinkMicrophoneInputGainMaximum = /* 'migx' */ 0x6D696778, /* Strings */ - BMDDeckLinkSerialPortDeviceName = 'slpn', - BMDDeckLinkVendorName = 'vndr', - BMDDeckLinkDisplayName = 'dspn', - BMDDeckLinkModelName = 'mdln', - BMDDeckLinkDeviceHandle = 'devh' + BMDDeckLinkSerialPortDeviceName = /* 'slpn' */ 0x736C706E, + BMDDeckLinkVendorName = /* 'vndr' */ 0x766E6472, + BMDDeckLinkDisplayName = /* 'dspn' */ 0x6473706E, + BMDDeckLinkModelName = /* 'mdln' */ 0x6D646C6E, + BMDDeckLinkDeviceHandle = /* 'devh' */ 0x64657668 }; /* Enum BMDDeckLinkAPIInformationID - DeckLinkAPI information ID */ typedef uint32_t BMDDeckLinkAPIInformationID; enum _BMDDeckLinkAPIInformationID { - BMDDeckLinkAPIVersion = 'vers' + + /* Integer or String */ + + BMDDeckLinkAPIVersion = /* 'vers' */ 0x76657273 }; /* Enum BMDDeckLinkStatusID - DeckLink Status ID */ @@ -531,28 +546,34 @@ enum _BMDDeckLinkStatusID { /* Integers */ - bmdDeckLinkStatusDetectedVideoInputMode = 'dvim', - bmdDeckLinkStatusDetectedVideoInputFlags = 'dvif', - bmdDeckLinkStatusCurrentVideoInputMode = 'cvim', - bmdDeckLinkStatusCurrentVideoInputPixelFormat = 'cvip', - bmdDeckLinkStatusCurrentVideoInputFlags = 'cvif', - bmdDeckLinkStatusCurrentVideoOutputMode = 'cvom', - bmdDeckLinkStatusCurrentVideoOutputFlags = 'cvof', - bmdDeckLinkStatusPCIExpressLinkWidth = 'pwid', - bmdDeckLinkStatusPCIExpressLinkSpeed = 'plnk', - bmdDeckLinkStatusLastVideoOutputPixelFormat = 'opix', - bmdDeckLinkStatusReferenceSignalMode = 'refm', - bmdDeckLinkStatusReferenceSignalFlags = 'reff', - bmdDeckLinkStatusDuplexMode = 'dupx', - bmdDeckLinkStatusBusy = 'busy', - bmdDeckLinkStatusInterchangeablePanelType = 'icpt', - bmdDeckLinkStatusDeviceTemperature = 'dtmp', + bmdDeckLinkStatusDetectedVideoInputMode = /* 'dvim' */ 0x6476696D, + bmdDeckLinkStatusDetectedVideoInputFormatFlags = /* 'dvff' */ 0x64766666, + bmdDeckLinkStatusDetectedVideoInputFieldDominance = /* 'dvfd' */ 0x64766664, + bmdDeckLinkStatusDetectedVideoInputColorspace = /* 'dscl' */ 0x6473636C, + bmdDeckLinkStatusDetectedVideoInputDynamicRange = /* 'dsdr' */ 0x64736472, + bmdDeckLinkStatusDetectedSDILinkConfiguration = /* 'dslc' */ 0x64736C63, + bmdDeckLinkStatusCurrentVideoInputMode = /* 'cvim' */ 0x6376696D, + bmdDeckLinkStatusCurrentVideoInputPixelFormat = /* 'cvip' */ 0x63766970, + bmdDeckLinkStatusCurrentVideoInputFlags = /* 'cvif' */ 0x63766966, + bmdDeckLinkStatusCurrentVideoOutputMode = /* 'cvom' */ 0x63766F6D, + bmdDeckLinkStatusCurrentVideoOutputFlags = /* 'cvof' */ 0x63766F66, + bmdDeckLinkStatusPCIExpressLinkWidth = /* 'pwid' */ 0x70776964, + bmdDeckLinkStatusPCIExpressLinkSpeed = /* 'plnk' */ 0x706C6E6B, + bmdDeckLinkStatusLastVideoOutputPixelFormat = /* 'opix' */ 0x6F706978, + bmdDeckLinkStatusReferenceSignalMode = /* 'refm' */ 0x7265666D, + bmdDeckLinkStatusReferenceSignalFlags = /* 'reff' */ 0x72656666, + bmdDeckLinkStatusBusy = /* 'busy' */ 0x62757379, + bmdDeckLinkStatusInterchangeablePanelType = /* 'icpt' */ 0x69637074, + bmdDeckLinkStatusDeviceTemperature = /* 'dtmp' */ 0x64746D70, /* Flags */ - bmdDeckLinkStatusVideoInputSignalLocked = 'visl', - bmdDeckLinkStatusReferenceSignalLocked = 'refl', - bmdDeckLinkStatusReceivedEDID = 'edid' + bmdDeckLinkStatusVideoInputSignalLocked = /* 'visl' */ 0x7669736C, + bmdDeckLinkStatusReferenceSignalLocked = /* 'refl' */ 0x7265666C, + + /* Bytes */ + + bmdDeckLinkStatusReceivedEDID = /* 'edid' */ 0x65646964 }; /* Enum BMDDeckLinkVideoStatusFlags - */ @@ -563,22 +584,22 @@ enum _BMDDeckLinkVideoStatusFlags { bmdDeckLinkVideoStatusDualStream3D = 1 << 1 }; -/* Enum BMDDuplexStatus - Duplex status of the device */ +/* Enum BMDDuplexMode - Duplex of the device */ -typedef uint32_t BMDDuplexStatus; -enum _BMDDuplexStatus { - bmdDuplexStatusFullDuplex = 'fdup', - bmdDuplexStatusHalfDuplex = 'hdup', - bmdDuplexStatusSimplex = 'splx', - bmdDuplexStatusInactive = 'inac' +typedef uint32_t BMDDuplexMode; +enum _BMDDuplexMode { + bmdDuplexFull = /* 'dxfu' */ 0x64786675, + bmdDuplexHalf = /* 'dxha' */ 0x64786861, + bmdDuplexSimplex = /* 'dxsp' */ 0x64787370, + bmdDuplexInactive = /* 'dxin' */ 0x6478696E }; /* Enum BMDPanelType - The type of interchangeable panel */ typedef uint32_t BMDPanelType; enum _BMDPanelType { - bmdPanelNotDetected = 'npnl', - bmdPanelTeranexMiniSmartPanel = 'tmsm' + bmdPanelNotDetected = /* 'npnl' */ 0x6E706E6C, + bmdPanelTeranexMiniSmartPanel = /* 'tmsm' */ 0x746D736D }; /* Enum BMDDeviceBusyState - Current device busy state */ @@ -602,19 +623,19 @@ enum _BMDVideoIOSupport { typedef uint32_t BMD3DPreviewFormat; enum _BMD3DPreviewFormat { - bmd3DPreviewFormatDefault = 'defa', - bmd3DPreviewFormatLeftOnly = 'left', - bmd3DPreviewFormatRightOnly = 'righ', - bmd3DPreviewFormatSideBySide = 'side', - bmd3DPreviewFormatTopBottom = 'topb' + bmd3DPreviewFormatDefault = /* 'defa' */ 0x64656661, + bmd3DPreviewFormatLeftOnly = /* 'left' */ 0x6C656674, + bmd3DPreviewFormatRightOnly = /* 'righ' */ 0x72696768, + bmd3DPreviewFormatSideBySide = /* 'side' */ 0x73696465, + bmd3DPreviewFormatTopBottom = /* 'topb' */ 0x746F7062 }; /* Enum BMDNotifications - Events that can be subscribed through IDeckLinkNotification */ typedef uint32_t BMDNotifications; enum _BMDNotifications { - bmdPreferencesChanged = 'pref', - bmdStatusChanged = 'stat' + bmdPreferencesChanged = /* 'pref' */ 0x70726566, + bmdStatusChanged = /* 'stat' */ 0x73746174 }; #if defined(__cplusplus) @@ -651,7 +672,11 @@ class IDeckLinkCocoaScreenPreviewCallback; class IDeckLinkGLScreenPreviewHelper; class IDeckLinkNotificationCallback; class IDeckLinkNotification; -class IDeckLinkAttributes; +class IDeckLinkProfileAttributes; +class IDeckLinkProfileIterator; +class IDeckLinkProfile; +class IDeckLinkProfileCallback; +class IDeckLinkProfileManager; class IDeckLinkStatus; class IDeckLinkKeyer; class IDeckLinkVideoConversion; @@ -663,7 +688,7 @@ class IDeckLinkDiscovery; class BMD_PUBLIC IDeckLinkVideoOutputCallback : public IUnknown { public: - virtual HRESULT ScheduledFrameCompleted (/* in */ IDeckLinkVideoFrame *completedFrame, /* in */ BMDOutputFrameCompletionResult result) = 0; + virtual HRESULT ScheduledFrameCompleted (/* in */ IDeckLinkVideoFrame* completedFrame, /* in */ BMDOutputFrameCompletionResult result) = 0; virtual HRESULT ScheduledPlaybackHasStopped (void) = 0; protected: @@ -675,7 +700,7 @@ protected: class BMD_PUBLIC IDeckLinkInputCallback : public IUnknown { public: - virtual HRESULT VideoInputFormatChanged (/* in */ BMDVideoInputFormatChangedEvents notificationEvents, /* in */ IDeckLinkDisplayMode *newDisplayMode, /* in */ BMDDetectedVideoInputFormatFlags detectedSignalFlags) = 0; + virtual HRESULT VideoInputFormatChanged (/* in */ BMDVideoInputFormatChangedEvents notificationEvents, /* in */ IDeckLinkDisplayMode* newDisplayMode, /* in */ BMDDetectedVideoInputFormatFlags detectedSignalFlags) = 0; virtual HRESULT VideoInputFrameArrived (/* in */ IDeckLinkVideoInputFrame* videoFrame, /* in */ IDeckLinkAudioInputPacket* audioPacket) = 0; protected: @@ -687,7 +712,7 @@ protected: class BMD_PUBLIC IDeckLinkEncoderInputCallback : public IUnknown { public: - virtual HRESULT VideoInputSignalChanged (/* in */ BMDVideoInputFormatChangedEvents notificationEvents, /* in */ IDeckLinkDisplayMode *newDisplayMode, /* in */ BMDDetectedVideoInputFormatFlags detectedSignalFlags) = 0; + virtual HRESULT VideoInputSignalChanged (/* in */ BMDVideoInputFormatChangedEvents notificationEvents, /* in */ IDeckLinkDisplayMode* newDisplayMode, /* in */ BMDDetectedVideoInputFormatFlags detectedSignalFlags) = 0; virtual HRESULT VideoPacketArrived (/* in */ IDeckLinkEncoderVideoPacket* videoPacket) = 0; virtual HRESULT AudioPacketArrived (/* in */ IDeckLinkEncoderAudioPacket* audioPacket) = 0; @@ -700,9 +725,8 @@ protected: class BMD_PUBLIC IDeckLinkMemoryAllocator : public IUnknown { public: - virtual HRESULT AllocateBuffer (/* in */ uint32_t bufferSize, /* out */ void **allocatedBuffer) = 0; - virtual HRESULT ReleaseBuffer (/* in */ void *buffer) = 0; - + virtual HRESULT AllocateBuffer (/* in */ uint32_t bufferSize, /* out */ void** allocatedBuffer) = 0; + virtual HRESULT ReleaseBuffer (/* in */ void* buffer) = 0; virtual HRESULT Commit (void) = 0; virtual HRESULT Decommit (void) = 0; }; @@ -715,12 +739,12 @@ public: virtual HRESULT RenderAudioSamples (/* in */ bool preroll) = 0; }; -/* Interface IDeckLinkIterator - enumerates installed DeckLink hardware */ +/* Interface IDeckLinkIterator - Enumerates installed DeckLink hardware */ class BMD_PUBLIC IDeckLinkIterator : public IUnknown { public: - virtual HRESULT Next (/* out */ IDeckLink **deckLinkInstance) = 0; + virtual HRESULT Next (/* out */ IDeckLink** deckLinkInstance) = 0; }; /* Interface IDeckLinkAPIInformation - DeckLinkAPI attribute interface */ @@ -728,10 +752,10 @@ public: class BMD_PUBLIC IDeckLinkAPIInformation : public IUnknown { public: - virtual HRESULT GetFlag (/* in */ BMDDeckLinkAPIInformationID cfgID, /* out */ bool *value) = 0; - virtual HRESULT GetInt (/* in */ BMDDeckLinkAPIInformationID cfgID, /* out */ int64_t *value) = 0; - virtual HRESULT GetFloat (/* in */ BMDDeckLinkAPIInformationID cfgID, /* out */ double *value) = 0; - virtual HRESULT GetString (/* in */ BMDDeckLinkAPIInformationID cfgID, /* out */ CFStringRef *value) = 0; + virtual HRESULT GetFlag (/* in */ BMDDeckLinkAPIInformationID cfgID, /* out */ bool* value) = 0; + virtual HRESULT GetInt (/* in */ BMDDeckLinkAPIInformationID cfgID, /* out */ int64_t* value) = 0; + virtual HRESULT GetFloat (/* in */ BMDDeckLinkAPIInformationID cfgID, /* out */ double* value) = 0; + virtual HRESULT GetString (/* in */ BMDDeckLinkAPIInformationID cfgID, /* out */ CFStringRef* value) = 0; protected: virtual ~IDeckLinkAPIInformation () {} // call Release method to drop reference count @@ -742,53 +766,47 @@ protected: class BMD_PUBLIC IDeckLinkOutput : public IUnknown { public: - virtual HRESULT DoesSupportVideoMode (/* in */ BMDDisplayMode displayMode, /* in */ BMDPixelFormat pixelFormat, /* in */ BMDVideoOutputFlags flags, /* out */ BMDDisplayModeSupport *result, /* out */ IDeckLinkDisplayMode **resultDisplayMode) = 0; - virtual HRESULT GetDisplayModeIterator (/* out */ IDeckLinkDisplayModeIterator **iterator) = 0; - - virtual HRESULT SetScreenPreviewCallback (/* in */ IDeckLinkScreenPreviewCallback *previewCallback) = 0; + virtual HRESULT DoesSupportVideoMode (/* in */ BMDVideoConnection connection /* If a value of bmdVideoConnectionUnspecified is specified, the caller does not care about the connection */, /* in */ BMDDisplayMode requestedMode, /* in */ BMDPixelFormat requestedPixelFormat, /* in */ BMDVideoOutputConversionMode conversionMode, /* in */ BMDSupportedVideoModeFlags flags, /* out */ BMDDisplayMode* actualMode, /* out */ bool* supported) = 0; + virtual HRESULT GetDisplayMode (/* in */ BMDDisplayMode displayMode, /* out */ IDeckLinkDisplayMode** resultDisplayMode) = 0; + virtual HRESULT GetDisplayModeIterator (/* out */ IDeckLinkDisplayModeIterator** iterator) = 0; + virtual HRESULT SetScreenPreviewCallback (/* in */ IDeckLinkScreenPreviewCallback* previewCallback) = 0; /* Video Output */ virtual HRESULT EnableVideoOutput (/* in */ BMDDisplayMode displayMode, /* in */ BMDVideoOutputFlags flags) = 0; virtual HRESULT DisableVideoOutput (void) = 0; - - virtual HRESULT SetVideoOutputFrameMemoryAllocator (/* in */ IDeckLinkMemoryAllocator *theAllocator) = 0; - virtual HRESULT CreateVideoFrame (/* in */ int32_t width, /* in */ int32_t height, /* in */ int32_t rowBytes, /* in */ BMDPixelFormat pixelFormat, /* in */ BMDFrameFlags flags, /* out */ IDeckLinkMutableVideoFrame **outFrame) = 0; - virtual HRESULT CreateAncillaryData (/* in */ BMDPixelFormat pixelFormat, /* out */ IDeckLinkVideoFrameAncillary **outBuffer) = 0; // Use of IDeckLinkVideoFrameAncillaryPackets is preferred - - virtual HRESULT DisplayVideoFrameSync (/* in */ IDeckLinkVideoFrame *theFrame) = 0; - virtual HRESULT ScheduleVideoFrame (/* in */ IDeckLinkVideoFrame *theFrame, /* in */ BMDTimeValue displayTime, /* in */ BMDTimeValue displayDuration, /* in */ BMDTimeScale timeScale) = 0; - virtual HRESULT SetScheduledFrameCompletionCallback (/* in */ IDeckLinkVideoOutputCallback *theCallback) = 0; - virtual HRESULT GetBufferedVideoFrameCount (/* out */ uint32_t *bufferedFrameCount) = 0; + virtual HRESULT SetVideoOutputFrameMemoryAllocator (/* in */ IDeckLinkMemoryAllocator* theAllocator) = 0; + virtual HRESULT CreateVideoFrame (/* in */ int32_t width, /* in */ int32_t height, /* in */ int32_t rowBytes, /* in */ BMDPixelFormat pixelFormat, /* in */ BMDFrameFlags flags, /* out */ IDeckLinkMutableVideoFrame** outFrame) = 0; + virtual HRESULT CreateAncillaryData (/* in */ BMDPixelFormat pixelFormat, /* out */ IDeckLinkVideoFrameAncillary** outBuffer) = 0; // Use of IDeckLinkVideoFrameAncillaryPackets is preferred + virtual HRESULT DisplayVideoFrameSync (/* in */ IDeckLinkVideoFrame* theFrame) = 0; + virtual HRESULT ScheduleVideoFrame (/* in */ IDeckLinkVideoFrame* theFrame, /* in */ BMDTimeValue displayTime, /* in */ BMDTimeValue displayDuration, /* in */ BMDTimeScale timeScale) = 0; + virtual HRESULT SetScheduledFrameCompletionCallback (/* in */ IDeckLinkVideoOutputCallback* theCallback) = 0; + virtual HRESULT GetBufferedVideoFrameCount (/* out */ uint32_t* bufferedFrameCount) = 0; /* Audio Output */ virtual HRESULT EnableAudioOutput (/* in */ BMDAudioSampleRate sampleRate, /* in */ BMDAudioSampleType sampleType, /* in */ uint32_t channelCount, /* in */ BMDAudioOutputStreamType streamType) = 0; virtual HRESULT DisableAudioOutput (void) = 0; - - virtual HRESULT WriteAudioSamplesSync (/* in */ void *buffer, /* in */ uint32_t sampleFrameCount, /* out */ uint32_t *sampleFramesWritten) = 0; - + virtual HRESULT WriteAudioSamplesSync (/* in */ void* buffer, /* in */ uint32_t sampleFrameCount, /* out */ uint32_t* sampleFramesWritten) = 0; virtual HRESULT BeginAudioPreroll (void) = 0; virtual HRESULT EndAudioPreroll (void) = 0; - virtual HRESULT ScheduleAudioSamples (/* in */ void *buffer, /* in */ uint32_t sampleFrameCount, /* in */ BMDTimeValue streamTime, /* in */ BMDTimeScale timeScale, /* out */ uint32_t *sampleFramesWritten) = 0; - - virtual HRESULT GetBufferedAudioSampleFrameCount (/* out */ uint32_t *bufferedSampleFrameCount) = 0; + virtual HRESULT ScheduleAudioSamples (/* in */ void* buffer, /* in */ uint32_t sampleFrameCount, /* in */ BMDTimeValue streamTime, /* in */ BMDTimeScale timeScale, /* out */ uint32_t* sampleFramesWritten) = 0; + virtual HRESULT GetBufferedAudioSampleFrameCount (/* out */ uint32_t* bufferedSampleFrameCount) = 0; virtual HRESULT FlushBufferedAudioSamples (void) = 0; - - virtual HRESULT SetAudioCallback (/* in */ IDeckLinkAudioOutputCallback *theCallback) = 0; + virtual HRESULT SetAudioCallback (/* in */ IDeckLinkAudioOutputCallback* theCallback) = 0; /* Output Control */ virtual HRESULT StartScheduledPlayback (/* in */ BMDTimeValue playbackStartTime, /* in */ BMDTimeScale timeScale, /* in */ double playbackSpeed) = 0; - virtual HRESULT StopScheduledPlayback (/* in */ BMDTimeValue stopPlaybackAtTime, /* out */ BMDTimeValue *actualStopTime, /* in */ BMDTimeScale timeScale) = 0; - virtual HRESULT IsScheduledPlaybackRunning (/* out */ bool *active) = 0; - virtual HRESULT GetScheduledStreamTime (/* in */ BMDTimeScale desiredTimeScale, /* out */ BMDTimeValue *streamTime, /* out */ double *playbackSpeed) = 0; - virtual HRESULT GetReferenceStatus (/* out */ BMDReferenceStatus *referenceStatus) = 0; + virtual HRESULT StopScheduledPlayback (/* in */ BMDTimeValue stopPlaybackAtTime, /* out */ BMDTimeValue* actualStopTime, /* in */ BMDTimeScale timeScale) = 0; + virtual HRESULT IsScheduledPlaybackRunning (/* out */ bool* active) = 0; + virtual HRESULT GetScheduledStreamTime (/* in */ BMDTimeScale desiredTimeScale, /* out */ BMDTimeValue* streamTime, /* out */ double* playbackSpeed) = 0; + virtual HRESULT GetReferenceStatus (/* out */ BMDReferenceStatus* referenceStatus) = 0; /* Hardware Timing */ - virtual HRESULT GetHardwareReferenceClock (/* in */ BMDTimeScale desiredTimeScale, /* out */ BMDTimeValue *hardwareTime, /* out */ BMDTimeValue *timeInFrame, /* out */ BMDTimeValue *ticksPerFrame) = 0; - virtual HRESULT GetFrameCompletionReferenceTimestamp (/* in */ IDeckLinkVideoFrame *theFrame, /* in */ BMDTimeScale desiredTimeScale, /* out */ BMDTimeValue *frameCompletionTimestamp) = 0; + virtual HRESULT GetHardwareReferenceClock (/* in */ BMDTimeScale desiredTimeScale, /* out */ BMDTimeValue* hardwareTime, /* out */ BMDTimeValue* timeInFrame, /* out */ BMDTimeValue* ticksPerFrame) = 0; + virtual HRESULT GetFrameCompletionReferenceTimestamp (/* in */ IDeckLinkVideoFrame* theFrame, /* in */ BMDTimeScale desiredTimeScale, /* out */ BMDTimeValue* frameCompletionTimestamp) = 0; protected: virtual ~IDeckLinkOutput () {} // call Release method to drop reference count @@ -799,23 +817,23 @@ protected: class BMD_PUBLIC IDeckLinkInput : public IUnknown { public: - virtual HRESULT DoesSupportVideoMode (/* in */ BMDDisplayMode displayMode, /* in */ BMDPixelFormat pixelFormat, /* in */ BMDVideoInputFlags flags, /* out */ BMDDisplayModeSupport *result, /* out */ IDeckLinkDisplayMode **resultDisplayMode) = 0; - virtual HRESULT GetDisplayModeIterator (/* out */ IDeckLinkDisplayModeIterator **iterator) = 0; - - virtual HRESULT SetScreenPreviewCallback (/* in */ IDeckLinkScreenPreviewCallback *previewCallback) = 0; + virtual HRESULT DoesSupportVideoMode (/* in */ BMDVideoConnection connection /* If a value of bmdVideoConnectionUnspecified is specified, the caller does not care about the connection */, /* in */ BMDDisplayMode requestedMode, /* in */ BMDPixelFormat requestedPixelFormat, /* in */ BMDVideoInputConversionMode conversionMode, /* in */ BMDSupportedVideoModeFlags flags, /* out */ BMDDisplayMode* actualMode, /* out */ bool* supported) = 0; + virtual HRESULT GetDisplayMode (/* in */ BMDDisplayMode displayMode, /* out */ IDeckLinkDisplayMode** resultDisplayMode) = 0; + virtual HRESULT GetDisplayModeIterator (/* out */ IDeckLinkDisplayModeIterator** iterator) = 0; + virtual HRESULT SetScreenPreviewCallback (/* in */ IDeckLinkScreenPreviewCallback* previewCallback) = 0; /* Video Input */ virtual HRESULT EnableVideoInput (/* in */ BMDDisplayMode displayMode, /* in */ BMDPixelFormat pixelFormat, /* in */ BMDVideoInputFlags flags) = 0; virtual HRESULT DisableVideoInput (void) = 0; - virtual HRESULT GetAvailableVideoFrameCount (/* out */ uint32_t *availableFrameCount) = 0; - virtual HRESULT SetVideoInputFrameMemoryAllocator (/* in */ IDeckLinkMemoryAllocator *theAllocator) = 0; + virtual HRESULT GetAvailableVideoFrameCount (/* out */ uint32_t* availableFrameCount) = 0; + virtual HRESULT SetVideoInputFrameMemoryAllocator (/* in */ IDeckLinkMemoryAllocator* theAllocator) = 0; /* Audio Input */ virtual HRESULT EnableAudioInput (/* in */ BMDAudioSampleRate sampleRate, /* in */ BMDAudioSampleType sampleType, /* in */ uint32_t channelCount) = 0; virtual HRESULT DisableAudioInput (void) = 0; - virtual HRESULT GetAvailableAudioSampleFrameCount (/* out */ uint32_t *availableSampleFrameCount) = 0; + virtual HRESULT GetAvailableAudioSampleFrameCount (/* out */ uint32_t* availableSampleFrameCount) = 0; /* Input Control */ @@ -823,11 +841,11 @@ public: virtual HRESULT StopStreams (void) = 0; virtual HRESULT PauseStreams (void) = 0; virtual HRESULT FlushStreams (void) = 0; - virtual HRESULT SetCallback (/* in */ IDeckLinkInputCallback *theCallback) = 0; + virtual HRESULT SetCallback (/* in */ IDeckLinkInputCallback* theCallback) = 0; /* Hardware Timing */ - virtual HRESULT GetHardwareReferenceClock (/* in */ BMDTimeScale desiredTimeScale, /* out */ BMDTimeValue *hardwareTime, /* out */ BMDTimeValue *timeInFrame, /* out */ BMDTimeValue *ticksPerFrame) = 0; + virtual HRESULT GetHardwareReferenceClock (/* in */ BMDTimeScale desiredTimeScale, /* out */ BMDTimeValue* hardwareTime, /* out */ BMDTimeValue* timeInFrame, /* out */ BMDTimeValue* ticksPerFrame) = 0; protected: virtual ~IDeckLinkInput () {} // call Release method to drop reference count @@ -839,7 +857,7 @@ class BMD_PUBLIC IDeckLinkHDMIInputEDID : public IUnknown { public: virtual HRESULT SetInt (/* in */ BMDDeckLinkHDMIInputEDIDID cfgID, /* in */ int64_t value) = 0; - virtual HRESULT GetInt (/* in */ BMDDeckLinkHDMIInputEDIDID cfgID, /* out */ int64_t *value) = 0; + virtual HRESULT GetInt (/* in */ BMDDeckLinkHDMIInputEDIDID cfgID, /* out */ int64_t* value) = 0; virtual HRESULT WriteToEDID (void) = 0; protected: @@ -851,21 +869,22 @@ protected: class BMD_PUBLIC IDeckLinkEncoderInput : public IUnknown { public: - virtual HRESULT DoesSupportVideoMode (/* in */ BMDDisplayMode displayMode, /* in */ BMDPixelFormat pixelFormat, /* in */ BMDVideoInputFlags flags, /* out */ BMDDisplayModeSupport *result, /* out */ IDeckLinkDisplayMode **resultDisplayMode) = 0; - virtual HRESULT GetDisplayModeIterator (/* out */ IDeckLinkDisplayModeIterator **iterator) = 0; + virtual HRESULT DoesSupportVideoMode (/* in */ BMDVideoConnection connection /* If a value of bmdVideoConnectionUnspecified is specified, the caller does not care about the connection */, /* in */ BMDDisplayMode requestedMode, /* in */ BMDPixelFormat requestedCodec, /* in */ uint32_t requestedCodecProfile, /* in */ BMDSupportedVideoModeFlags flags, /* out */ bool* supported) = 0; + virtual HRESULT GetDisplayMode (/* in */ BMDDisplayMode displayMode, /* out */ IDeckLinkDisplayMode** resultDisplayMode) = 0; + virtual HRESULT GetDisplayModeIterator (/* out */ IDeckLinkDisplayModeIterator** iterator) = 0; /* Video Input */ virtual HRESULT EnableVideoInput (/* in */ BMDDisplayMode displayMode, /* in */ BMDPixelFormat pixelFormat, /* in */ BMDVideoInputFlags flags) = 0; virtual HRESULT DisableVideoInput (void) = 0; - virtual HRESULT GetAvailablePacketsCount (/* out */ uint32_t *availablePacketsCount) = 0; - virtual HRESULT SetMemoryAllocator (/* in */ IDeckLinkMemoryAllocator *theAllocator) = 0; + virtual HRESULT GetAvailablePacketsCount (/* out */ uint32_t* availablePacketsCount) = 0; + virtual HRESULT SetMemoryAllocator (/* in */ IDeckLinkMemoryAllocator* theAllocator) = 0; /* Audio Input */ virtual HRESULT EnableAudioInput (/* in */ BMDAudioFormat audioFormat, /* in */ BMDAudioSampleRate sampleRate, /* in */ BMDAudioSampleType sampleType, /* in */ uint32_t channelCount) = 0; virtual HRESULT DisableAudioInput (void) = 0; - virtual HRESULT GetAvailableAudioSampleFrameCount (/* out */ uint32_t *availableSampleFrameCount) = 0; + virtual HRESULT GetAvailableAudioSampleFrameCount (/* out */ uint32_t* availableSampleFrameCount) = 0; /* Input Control */ @@ -873,11 +892,11 @@ public: virtual HRESULT StopStreams (void) = 0; virtual HRESULT PauseStreams (void) = 0; virtual HRESULT FlushStreams (void) = 0; - virtual HRESULT SetCallback (/* in */ IDeckLinkEncoderInputCallback *theCallback) = 0; + virtual HRESULT SetCallback (/* in */ IDeckLinkEncoderInputCallback* theCallback) = 0; /* Hardware Timing */ - virtual HRESULT GetHardwareReferenceClock (/* in */ BMDTimeScale desiredTimeScale, /* out */ BMDTimeValue *hardwareTime, /* out */ BMDTimeValue *timeInFrame, /* out */ BMDTimeValue *ticksPerFrame) = 0; + virtual HRESULT GetHardwareReferenceClock (/* in */ BMDTimeScale desiredTimeScale, /* out */ BMDTimeValue* hardwareTime, /* out */ BMDTimeValue* timeInFrame, /* out */ BMDTimeValue* ticksPerFrame) = 0; protected: virtual ~IDeckLinkEncoderInput () {} // call Release method to drop reference count @@ -893,10 +912,9 @@ public: virtual long GetRowBytes (void) = 0; virtual BMDPixelFormat GetPixelFormat (void) = 0; virtual BMDFrameFlags GetFlags (void) = 0; - virtual HRESULT GetBytes (/* out */ void **buffer) = 0; - - virtual HRESULT GetTimecode (/* in */ BMDTimecodeFormat format, /* out */ IDeckLinkTimecode **timecode) = 0; - virtual HRESULT GetAncillaryData (/* out */ IDeckLinkVideoFrameAncillary **ancillary) = 0; // Use of IDeckLinkVideoFrameAncillaryPackets is preferred + virtual HRESULT GetBytes (/* out */ void** buffer) = 0; + virtual HRESULT GetTimecode (/* in */ BMDTimecodeFormat format, /* out */ IDeckLinkTimecode** timecode) = 0; + virtual HRESULT GetAncillaryData (/* out */ IDeckLinkVideoFrameAncillary** ancillary) = 0; // Use of IDeckLinkVideoFrameAncillaryPackets is preferred protected: virtual ~IDeckLinkVideoFrame () {} // call Release method to drop reference count @@ -908,10 +926,9 @@ class BMD_PUBLIC IDeckLinkMutableVideoFrame : public IDeckLinkVideoFrame { public: virtual HRESULT SetFlags (/* in */ BMDFrameFlags newFlags) = 0; - - virtual HRESULT SetTimecode (/* in */ BMDTimecodeFormat format, /* in */ IDeckLinkTimecode *timecode) = 0; + virtual HRESULT SetTimecode (/* in */ BMDTimecodeFormat format, /* in */ IDeckLinkTimecode* timecode) = 0; virtual HRESULT SetTimecodeFromComponents (/* in */ BMDTimecodeFormat format, /* in */ uint8_t hours, /* in */ uint8_t minutes, /* in */ uint8_t seconds, /* in */ uint8_t frames, /* in */ BMDTimecodeFlags flags) = 0; - virtual HRESULT SetAncillaryData (/* in */ IDeckLinkVideoFrameAncillary *ancillary) = 0; + virtual HRESULT SetAncillaryData (/* in */ IDeckLinkVideoFrameAncillary* ancillary) = 0; virtual HRESULT SetTimecodeUserBits (/* in */ BMDTimecodeFormat format, /* in */ BMDTimecodeUserBits userBits) = 0; protected: @@ -924,21 +941,22 @@ class BMD_PUBLIC IDeckLinkVideoFrame3DExtensions : public IUnknown { public: virtual BMDVideo3DPackingFormat Get3DPackingFormat (void) = 0; - virtual HRESULT GetFrameForRightEye (/* out */ IDeckLinkVideoFrame* *rightEyeFrame) = 0; + virtual HRESULT GetFrameForRightEye (/* out */ IDeckLinkVideoFrame** rightEyeFrame) = 0; protected: virtual ~IDeckLinkVideoFrame3DExtensions () {} // call Release method to drop reference count }; -/* Interface IDeckLinkVideoFrameMetadataExtensions - Optional interface implemented on IDeckLinkVideoFrame to support frame metadata such as HDMI HDR information */ +/* Interface IDeckLinkVideoFrameMetadataExtensions - Optional interface implemented on IDeckLinkVideoFrame to support frame metadata such as HDR information */ class BMD_PUBLIC IDeckLinkVideoFrameMetadataExtensions : public IUnknown { public: - virtual HRESULT GetInt (/* in */ BMDDeckLinkFrameMetadataID metadataID, /* out */ int64_t *value) = 0; - virtual HRESULT GetFloat (/* in */ BMDDeckLinkFrameMetadataID metadataID, /* out */ double *value) = 0; + virtual HRESULT GetInt (/* in */ BMDDeckLinkFrameMetadataID metadataID, /* out */ int64_t* value) = 0; + virtual HRESULT GetFloat (/* in */ BMDDeckLinkFrameMetadataID metadataID, /* out */ double* value) = 0; virtual HRESULT GetFlag (/* in */ BMDDeckLinkFrameMetadataID metadataID, /* out */ bool* value) = 0; - virtual HRESULT GetString (/* in */ BMDDeckLinkFrameMetadataID metadataID, /* out */ CFStringRef *value) = 0; + virtual HRESULT GetString (/* in */ BMDDeckLinkFrameMetadataID metadataID, /* out */ CFStringRef* value) = 0; + virtual HRESULT GetBytes (/* in */ BMDDeckLinkFrameMetadataID metadataID, /* out */ void* buffer /* optional */, /* in, out */ uint32_t* bufferSize) = 0; protected: virtual ~IDeckLinkVideoFrameMetadataExtensions () {} // call Release method to drop reference count @@ -949,8 +967,8 @@ protected: class BMD_PUBLIC IDeckLinkVideoInputFrame : public IDeckLinkVideoFrame { public: - virtual HRESULT GetStreamTime (/* out */ BMDTimeValue *frameTime, /* out */ BMDTimeValue *frameDuration, /* in */ BMDTimeScale timeScale) = 0; - virtual HRESULT GetHardwareReferenceTimestamp (/* in */ BMDTimeScale timeScale, /* out */ BMDTimeValue *frameTime, /* out */ BMDTimeValue *frameDuration) = 0; + virtual HRESULT GetStreamTime (/* out */ BMDTimeValue* frameTime, /* out */ BMDTimeValue* frameDuration, /* in */ BMDTimeScale timeScale) = 0; + virtual HRESULT GetHardwareReferenceTimestamp (/* in */ BMDTimeScale timeScale, /* out */ BMDTimeValue* frameTime, /* out */ BMDTimeValue* frameDuration) = 0; protected: virtual ~IDeckLinkVideoInputFrame () {} // call Release method to drop reference count @@ -961,12 +979,11 @@ protected: class BMD_PUBLIC IDeckLinkAncillaryPacket : public IUnknown { public: - - virtual HRESULT GetBytes (/* in */ BMDAncillaryPacketFormat format /* For output, only one format need be offered */, /* out */ const void **data /* Optional */, /* out */ uint32_t *size /* Optional */) = 0; + virtual HRESULT GetBytes (/* in */ BMDAncillaryPacketFormat format /* For output, only one format need be offered */, /* out */ const void** data /* Optional */, /* out */ uint32_t* size /* Optional */) = 0; virtual uint8_t GetDID (void) = 0; virtual uint8_t GetSDID (void) = 0; - virtual uint32_t GetLineNumber (void) = 0; // On output, zero is auto - virtual uint8_t GetDataStreamIndex (void) = 0; // Usually zero. Can only be 1 if non-SD and the first data stream is completely full + virtual uint32_t GetLineNumber (void) = 0; // On output, zero is auto + virtual uint8_t GetDataStreamIndex (void) = 0; // Usually zero. Can only be 1 if non-SD and the first data stream is completely full protected: virtual ~IDeckLinkAncillaryPacket () {} // call Release method to drop reference count @@ -977,35 +994,33 @@ protected: class BMD_PUBLIC IDeckLinkAncillaryPacketIterator : public IUnknown { public: - virtual HRESULT Next (/* out */ IDeckLinkAncillaryPacket **packet) = 0; + virtual HRESULT Next (/* out */ IDeckLinkAncillaryPacket** packet) = 0; protected: virtual ~IDeckLinkAncillaryPacketIterator () {} // call Release method to drop reference count }; -/* Interface IDeckLinkVideoFrameAncillaryPackets - Obtained through QueryInterface() on an IDeckLinkVideoFrame object. */ +/* Interface IDeckLinkVideoFrameAncillaryPackets - Obtained through QueryInterface on an IDeckLinkVideoFrame object. */ class BMD_PUBLIC IDeckLinkVideoFrameAncillaryPackets : public IUnknown { public: - - virtual HRESULT GetPacketIterator (/* out */ IDeckLinkAncillaryPacketIterator **iterator) = 0; - virtual HRESULT GetFirstPacketByID (/* in */ uint8_t DID, /* in */ uint8_t SDID, /* out */ IDeckLinkAncillaryPacket **packet) = 0; - virtual HRESULT AttachPacket (/* in */ IDeckLinkAncillaryPacket *packet) = 0; // Implement IDeckLinkAncillaryPacket to output your own - virtual HRESULT DetachPacket (/* in */ IDeckLinkAncillaryPacket *packet) = 0; + virtual HRESULT GetPacketIterator (/* out */ IDeckLinkAncillaryPacketIterator** iterator) = 0; + virtual HRESULT GetFirstPacketByID (/* in */ uint8_t DID, /* in */ uint8_t SDID, /* out */ IDeckLinkAncillaryPacket** packet) = 0; + virtual HRESULT AttachPacket (/* in */ IDeckLinkAncillaryPacket* packet) = 0; // Implement IDeckLinkAncillaryPacket to output your own + virtual HRESULT DetachPacket (/* in */ IDeckLinkAncillaryPacket* packet) = 0; virtual HRESULT DetachAllPackets (void) = 0; protected: virtual ~IDeckLinkVideoFrameAncillaryPackets () {} // call Release method to drop reference count }; -/* Interface IDeckLinkVideoFrameAncillary - Use of IDeckLinkVideoFrameAncillaryPackets is preferred. Obtained through QueryInterface() on an IDeckLinkVideoFrame object. */ +/* Interface IDeckLinkVideoFrameAncillary - Use of IDeckLinkVideoFrameAncillaryPackets is preferred. Obtained through QueryInterface on an IDeckLinkVideoFrame object. */ class BMD_PUBLIC IDeckLinkVideoFrameAncillary : public IUnknown { public: - - virtual HRESULT GetBufferForVerticalBlankingLine (/* in */ uint32_t lineNumber, /* out */ void **buffer) = 0; // Pixels/rowbytes is same as display mode, except for above HD where it's 1920 pixels for UHD modes and 2048 pixels for DCI modes + virtual HRESULT GetBufferForVerticalBlankingLine (/* in */ uint32_t lineNumber, /* out */ void** buffer) = 0; // Pixels/rowbytes is same as display mode, except for above HD where it's 1920 pixels for UHD modes and 2048 pixels for DCI modes virtual BMDPixelFormat GetPixelFormat (void) = 0; virtual BMDDisplayMode GetDisplayMode (void) = 0; @@ -1018,9 +1033,9 @@ protected: class BMD_PUBLIC IDeckLinkEncoderPacket : public IUnknown { public: - virtual HRESULT GetBytes (/* out */ void **buffer) = 0; + virtual HRESULT GetBytes (/* out */ void** buffer) = 0; virtual long GetSize (void) = 0; - virtual HRESULT GetStreamTime (/* out */ BMDTimeValue *frameTime, /* in */ BMDTimeScale timeScale) = 0; + virtual HRESULT GetStreamTime (/* out */ BMDTimeValue* frameTime, /* in */ BMDTimeScale timeScale) = 0; virtual BMDPacketType GetPacketType (void) = 0; protected: @@ -1033,9 +1048,8 @@ class BMD_PUBLIC IDeckLinkEncoderVideoPacket : public IDeckLinkEncoderPacket { public: virtual BMDPixelFormat GetPixelFormat (void) = 0; - virtual HRESULT GetHardwareReferenceTimestamp (/* in */ BMDTimeScale timeScale, /* out */ BMDTimeValue *frameTime, /* out */ BMDTimeValue *frameDuration) = 0; - - virtual HRESULT GetTimecode (/* in */ BMDTimecodeFormat format, /* out */ IDeckLinkTimecode **timecode) = 0; + virtual HRESULT GetHardwareReferenceTimestamp (/* in */ BMDTimeScale timeScale, /* out */ BMDTimeValue* frameTime, /* out */ BMDTimeValue* frameDuration) = 0; + virtual HRESULT GetTimecode (/* in */ BMDTimecodeFormat format, /* out */ IDeckLinkTimecode** timecode) = 0; protected: virtual ~IDeckLinkEncoderVideoPacket () {} // call Release method to drop reference count @@ -1052,13 +1066,13 @@ protected: virtual ~IDeckLinkEncoderAudioPacket () {} // call Release method to drop reference count }; -/* Interface IDeckLinkH265NALPacket - Obtained through QueryInterface() on an IDeckLinkEncoderVideoPacket object */ +/* Interface IDeckLinkH265NALPacket - Obtained through QueryInterface on an IDeckLinkEncoderVideoPacket object */ class BMD_PUBLIC IDeckLinkH265NALPacket : public IDeckLinkEncoderVideoPacket { public: - virtual HRESULT GetUnitType (/* out */ uint8_t *unitType) = 0; - virtual HRESULT GetBytesNoPrefix (/* out */ void **buffer) = 0; + virtual HRESULT GetUnitType (/* out */ uint8_t* unitType) = 0; + virtual HRESULT GetBytesNoPrefix (/* out */ void** buffer) = 0; virtual long GetSizeNoPrefix (void) = 0; protected: @@ -1071,8 +1085,8 @@ class BMD_PUBLIC IDeckLinkAudioInputPacket : public IUnknown { public: virtual long GetSampleFrameCount (void) = 0; - virtual HRESULT GetBytes (/* out */ void **buffer) = 0; - virtual HRESULT GetPacketTime (/* out */ BMDTimeValue *packetTime, /* in */ BMDTimeScale timeScale) = 0; + virtual HRESULT GetBytes (/* out */ void** buffer) = 0; + virtual HRESULT GetPacketTime (/* out */ BMDTimeValue* packetTime, /* in */ BMDTimeScale timeScale) = 0; protected: virtual ~IDeckLinkAudioInputPacket () {} // call Release method to drop reference count @@ -1083,13 +1097,13 @@ protected: class BMD_PUBLIC IDeckLinkScreenPreviewCallback : public IUnknown { public: - virtual HRESULT DrawFrame (/* in */ IDeckLinkVideoFrame *theFrame) = 0; + virtual HRESULT DrawFrame (/* in */ IDeckLinkVideoFrame* theFrame) = 0; protected: virtual ~IDeckLinkScreenPreviewCallback () {} // call Release method to drop reference count }; -/* Interface IDeckLinkCocoaScreenPreviewCallback - Screen preview callback for Cocoa-based applications */ +/* Interface IDeckLinkCocoaScreenPreviewCallback - Screen preview callback for Cocoa-based applications. Created with CreateCocoaScreenPreview */ class BMD_PUBLIC IDeckLinkCocoaScreenPreviewCallback : public IDeckLinkScreenPreviewCallback { @@ -1099,7 +1113,7 @@ protected: virtual ~IDeckLinkCocoaScreenPreviewCallback () {} // call Release method to drop reference count }; -/* Interface IDeckLinkGLScreenPreviewHelper - Created with CoCreateInstance(). */ +/* Interface IDeckLinkGLScreenPreviewHelper - Created with CoCreateInstance on platforms with native COM support or from CreateOpenGLScreenPreviewHelper on other platforms. */ class BMD_PUBLIC IDeckLinkGLScreenPreviewHelper : public IUnknown { @@ -1109,7 +1123,7 @@ public: virtual HRESULT InitializeGL (void) = 0; virtual HRESULT PaintGL (void) = 0; - virtual HRESULT SetFrame (/* in */ IDeckLinkVideoFrame *theFrame) = 0; + virtual HRESULT SetFrame (/* in */ IDeckLinkVideoFrame* theFrame) = 0; virtual HRESULT Set3DPreviewFormat (/* in */ BMD3DPreviewFormat previewFormat) = 0; protected: @@ -1129,22 +1143,75 @@ public: class BMD_PUBLIC IDeckLinkNotification : public IUnknown { public: - virtual HRESULT Subscribe (/* in */ BMDNotifications topic, /* in */ IDeckLinkNotificationCallback *theCallback) = 0; - virtual HRESULT Unsubscribe (/* in */ BMDNotifications topic, /* in */ IDeckLinkNotificationCallback *theCallback) = 0; -}; - -/* Interface IDeckLinkAttributes - DeckLink Attribute interface */ - -class BMD_PUBLIC IDeckLinkAttributes : public IUnknown -{ -public: - virtual HRESULT GetFlag (/* in */ BMDDeckLinkAttributeID cfgID, /* out */ bool *value) = 0; - virtual HRESULT GetInt (/* in */ BMDDeckLinkAttributeID cfgID, /* out */ int64_t *value) = 0; - virtual HRESULT GetFloat (/* in */ BMDDeckLinkAttributeID cfgID, /* out */ double *value) = 0; - virtual HRESULT GetString (/* in */ BMDDeckLinkAttributeID cfgID, /* out */ CFStringRef *value) = 0; + virtual HRESULT Subscribe (/* in */ BMDNotifications topic, /* in */ IDeckLinkNotificationCallback* theCallback) = 0; + virtual HRESULT Unsubscribe (/* in */ BMDNotifications topic, /* in */ IDeckLinkNotificationCallback* theCallback) = 0; protected: - virtual ~IDeckLinkAttributes () {} // call Release method to drop reference count + virtual ~IDeckLinkNotification () {} // call Release method to drop reference count +}; + +/* Interface IDeckLinkProfileAttributes - Created by QueryInterface from an IDeckLinkProfile, or from IDeckLink. When queried from IDeckLink, interrogates the active profile */ + +class BMD_PUBLIC IDeckLinkProfileAttributes : public IUnknown +{ +public: + virtual HRESULT GetFlag (/* in */ BMDDeckLinkAttributeID cfgID, /* out */ bool* value) = 0; + virtual HRESULT GetInt (/* in */ BMDDeckLinkAttributeID cfgID, /* out */ int64_t* value) = 0; + virtual HRESULT GetFloat (/* in */ BMDDeckLinkAttributeID cfgID, /* out */ double* value) = 0; + virtual HRESULT GetString (/* in */ BMDDeckLinkAttributeID cfgID, /* out */ CFStringRef* value) = 0; + +protected: + virtual ~IDeckLinkProfileAttributes () {} // call Release method to drop reference count +}; + +/* Interface IDeckLinkProfileIterator - Enumerates IDeckLinkProfile interfaces */ + +class BMD_PUBLIC IDeckLinkProfileIterator : public IUnknown +{ +public: + virtual HRESULT Next (/* out */ IDeckLinkProfile** profile) = 0; + +protected: + virtual ~IDeckLinkProfileIterator () {} // call Release method to drop reference count +}; + +/* Interface IDeckLinkProfile - Represents the active profile when queried from IDeckLink */ + +class BMD_PUBLIC IDeckLinkProfile : public IUnknown +{ +public: + virtual HRESULT GetDevice (/* out */ IDeckLink** device) = 0; // Device affected when this profile becomes active + virtual HRESULT IsActive (/* out */ bool* isActive) = 0; + virtual HRESULT SetActive (void) = 0; // Activating a profile will also change the profile on all devices enumerated by GetPeers. Activation is not complete until IDeckLinkProfileCallback::ProfileActivated is called + virtual HRESULT GetPeers (/* out */ IDeckLinkProfileIterator** profileIterator) = 0; // Profiles of other devices activated with this profile + +protected: + virtual ~IDeckLinkProfile () {} // call Release method to drop reference count +}; + +/* Interface IDeckLinkProfileCallback - Receive notifications about profiles related to this device */ + +class BMD_PUBLIC IDeckLinkProfileCallback : public IUnknown +{ +public: + virtual HRESULT ProfileChanging (/* in */ IDeckLinkProfile* profileToBeActivated, /* in */ bool streamsWillBeForcedToStop) = 0; // Called before this device changes profile. User has an opportunity for teardown if streamsWillBeForcedToStop + virtual HRESULT ProfileActivated (/* in */ IDeckLinkProfile* activatedProfile) = 0; // Called after this device has been activated with a new profile + +protected: + virtual ~IDeckLinkProfileCallback () {} // call Release method to drop reference count +}; + +/* Interface IDeckLinkProfileManager - Created by QueryInterface from IDeckLink when a device has multiple optional profiles */ + +class BMD_PUBLIC IDeckLinkProfileManager : public IUnknown +{ +public: + virtual HRESULT GetProfiles (/* out */ IDeckLinkProfileIterator** profileIterator) = 0; // All available profiles for this device + virtual HRESULT GetProfile (/* in */ BMDProfileID profileID, /* out */ IDeckLinkProfile** profile) = 0; + virtual HRESULT SetCallback (/* in */ IDeckLinkProfileCallback* callback) = 0; + +protected: + virtual ~IDeckLinkProfileManager () {} // call Release method to drop reference count }; /* Interface IDeckLinkStatus - DeckLink Status interface */ @@ -1152,11 +1219,11 @@ protected: class BMD_PUBLIC IDeckLinkStatus : public IUnknown { public: - virtual HRESULT GetFlag (/* in */ BMDDeckLinkStatusID statusID, /* out */ bool *value) = 0; - virtual HRESULT GetInt (/* in */ BMDDeckLinkStatusID statusID, /* out */ int64_t *value) = 0; - virtual HRESULT GetFloat (/* in */ BMDDeckLinkStatusID statusID, /* out */ double *value) = 0; - virtual HRESULT GetString (/* in */ BMDDeckLinkStatusID statusID, /* out */ CFStringRef *value) = 0; - virtual HRESULT GetBytes (/* in */ BMDDeckLinkStatusID statusID, /* out */ void *buffer, /* in, out */ uint32_t *bufferSize) = 0; + virtual HRESULT GetFlag (/* in */ BMDDeckLinkStatusID statusID, /* out */ bool* value) = 0; + virtual HRESULT GetInt (/* in */ BMDDeckLinkStatusID statusID, /* out */ int64_t* value) = 0; + virtual HRESULT GetFloat (/* in */ BMDDeckLinkStatusID statusID, /* out */ double* value) = 0; + virtual HRESULT GetString (/* in */ BMDDeckLinkStatusID statusID, /* out */ CFStringRef* value) = 0; + virtual HRESULT GetBytes (/* in */ BMDDeckLinkStatusID statusID, /* out */ void* buffer, /* in, out */ uint32_t* bufferSize) = 0; protected: virtual ~IDeckLinkStatus () {} // call Release method to drop reference count @@ -1177,7 +1244,7 @@ protected: virtual ~IDeckLinkKeyer () {} // call Release method to drop reference count }; -/* Interface IDeckLinkVideoConversion - Created with CoCreateInstance(). */ +/* Interface IDeckLinkVideoConversion - Created with CoCreateInstance. */ class BMD_PUBLIC IDeckLinkVideoConversion : public IUnknown { @@ -1216,16 +1283,15 @@ protected: extern "C" { - IDeckLinkIterator* BMD_PUBLIC CreateDeckLinkIteratorInstance (void); - IDeckLinkDiscovery* BMD_PUBLIC CreateDeckLinkDiscoveryInstance (void); - IDeckLinkAPIInformation* BMD_PUBLIC CreateDeckLinkAPIInformationInstance (void); - IDeckLinkGLScreenPreviewHelper* BMD_PUBLIC CreateOpenGLScreenPreviewHelper (void); - IDeckLinkCocoaScreenPreviewCallback* BMD_PUBLIC CreateCocoaScreenPreview (void* /* (NSView*) */ parentView); - IDeckLinkVideoConversion* BMD_PUBLIC CreateVideoConversionInstance (void); - IDeckLinkVideoFrameAncillaryPackets* BMD_PUBLIC CreateVideoFrameAncillaryPacketsInstance (void); // For use when creating a custom IDeckLinkVideoFrame without wrapping IDeckLinkOutput::CreateVideoFrame + IDeckLinkIterator* BMD_PUBLIC CreateDeckLinkIteratorInstance(void); + IDeckLinkDiscovery* BMD_PUBLIC CreateDeckLinkDiscoveryInstance(void); + IDeckLinkAPIInformation* BMD_PUBLIC CreateDeckLinkAPIInformationInstance(void); + IDeckLinkGLScreenPreviewHelper* BMD_PUBLIC CreateOpenGLScreenPreviewHelper(void); + IDeckLinkCocoaScreenPreviewCallback* BMD_PUBLIC CreateCocoaScreenPreview(/* in */ void* /* (NSView*)*/ parentView); + IDeckLinkVideoConversion* BMD_PUBLIC CreateVideoConversionInstance(void); + IDeckLinkVideoFrameAncillaryPackets* BMD_PUBLIC CreateVideoFrameAncillaryPacketsInstance(void); // For use when creating a custom IDeckLinkVideoFrame without wrapping IDeckLinkOutput::CreateVideoFrame } - -#endif // defined(__cplusplus) +#endif /* defined(__cplusplus) */ #endif /* defined(BMD_DECKLINKAPI_H) */ diff --git a/plugins/decklink/mac/decklink-sdk/DeckLinkAPIConfiguration.h b/plugins/decklink/mac/decklink-sdk/DeckLinkAPIConfiguration.h index a76d33a..cd115bd 100644 --- a/plugins/decklink/mac/decklink-sdk/DeckLinkAPIConfiguration.h +++ b/plugins/decklink/mac/decklink-sdk/DeckLinkAPIConfiguration.h @@ -1,5 +1,5 @@ /* -LICENSE-START- -** Copyright (c) 2018 Blackmagic Design +** Copyright (c) 2020 Blackmagic Design ** ** Permission is hereby granted, free of charge, to any person or organization ** obtaining a copy of the software and accompanying documentation covered by @@ -7,14 +7,14 @@ ** execute, and transmit the Software, and to prepare derivative works of the ** Software, and to permit third-parties to whom the Software is furnished to ** do so, all subject to the following: -** +** ** The copyright notices in the Software and this entire statement, including ** the above license grant, this restriction and the following disclaimer, ** must be included in all copies of the Software, in whole or in part, and ** all derivative works of the Software, unless such copies or derivative ** works are solely in the form of machine-executable object code generated by ** a source language processor. -** +** ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT @@ -46,8 +46,8 @@ // Interface ID Declarations -BMD_CONST REFIID IID_IDeckLinkConfiguration = /* EF90380B-4AE5-4346-9077-E288E149F129 */ {0xEF,0x90,0x38,0x0B,0x4A,0xE5,0x43,0x46,0x90,0x77,0xE2,0x88,0xE1,0x49,0xF1,0x29}; -BMD_CONST REFIID IID_IDeckLinkEncoderConfiguration = /* 138050E5-C60A-4552-BF3F-0F358049327E */ {0x13,0x80,0x50,0xE5,0xC6,0x0A,0x45,0x52,0xBF,0x3F,0x0F,0x35,0x80,0x49,0x32,0x7E}; +BMD_CONST REFIID IID_IDeckLinkConfiguration = /* 912F634B-2D4E-40A4-8AAB-8D80B73F1289 */ { 0x91,0x2F,0x63,0x4B,0x2D,0x4E,0x40,0xA4,0x8A,0xAB,0x8D,0x80,0xB7,0x3F,0x12,0x89 }; +BMD_CONST REFIID IID_IDeckLinkEncoderConfiguration = /* 138050E5-C60A-4552-BF3F-0F358049327E */ { 0x13,0x80,0x50,0xE5,0xC6,0x0A,0x45,0x52,0xBF,0x3F,0x0F,0x35,0x80,0x49,0x32,0x7E }; /* Enum BMDDeckLinkConfigurationID - DeckLink Configuration ID */ @@ -56,129 +56,131 @@ enum _BMDDeckLinkConfigurationID { /* Serial port Flags */ - bmdDeckLinkConfigSwapSerialRxTx = 'ssrt', + bmdDeckLinkConfigSwapSerialRxTx = /* 'ssrt' */ 0x73737274, /* Video Input/Output Integers */ - bmdDeckLinkConfigHDMI3DPackingFormat = '3dpf', - bmdDeckLinkConfigBypass = 'byps', - bmdDeckLinkConfigClockTimingAdjustment = 'ctad', - bmdDeckLinkConfigDuplexMode = 'dupx', + bmdDeckLinkConfigHDMI3DPackingFormat = /* '3dpf' */ 0x33647066, + bmdDeckLinkConfigBypass = /* 'byps' */ 0x62797073, + bmdDeckLinkConfigClockTimingAdjustment = /* 'ctad' */ 0x63746164, /* Audio Input/Output Flags */ - bmdDeckLinkConfigAnalogAudioConsumerLevels = 'aacl', - - /* Video output flags */ - - bmdDeckLinkConfigFieldFlickerRemoval = 'fdfr', - bmdDeckLinkConfigHD1080p24ToHD1080i5994Conversion = 'to59', - bmdDeckLinkConfig444SDIVideoOutput = '444o', - bmdDeckLinkConfigBlackVideoOutputDuringCapture = 'bvoc', - bmdDeckLinkConfigLowLatencyVideoOutput = 'llvo', - bmdDeckLinkConfigDownConversionOnAllAnalogOutput = 'caao', - bmdDeckLinkConfigSMPTELevelAOutput = 'smta', - bmdDeckLinkConfigRec2020Output = 'rec2', // Ensure output is Rec.2020 colorspace - bmdDeckLinkConfigQuadLinkSDIVideoOutputSquareDivisionSplit = 'SDQS', + bmdDeckLinkConfigAnalogAudioConsumerLevels = /* 'aacl' */ 0x6161636C, + bmdDeckLinkConfigSwapHDMICh3AndCh4OnInput = /* 'hi34' */ 0x68693334, + bmdDeckLinkConfigSwapHDMICh3AndCh4OnOutput = /* 'ho34' */ 0x686F3334, /* Video Output Flags */ - bmdDeckLinkConfigOutput1080pAsPsF = 'pfpr', + bmdDeckLinkConfigFieldFlickerRemoval = /* 'fdfr' */ 0x66646672, + bmdDeckLinkConfigHD1080p24ToHD1080i5994Conversion = /* 'to59' */ 0x746F3539, + bmdDeckLinkConfig444SDIVideoOutput = /* '444o' */ 0x3434346F, + bmdDeckLinkConfigBlackVideoOutputDuringCapture = /* 'bvoc' */ 0x62766F63, + bmdDeckLinkConfigLowLatencyVideoOutput = /* 'llvo' */ 0x6C6C766F, + bmdDeckLinkConfigDownConversionOnAllAnalogOutput = /* 'caao' */ 0x6361616F, + bmdDeckLinkConfigSMPTELevelAOutput = /* 'smta' */ 0x736D7461, + bmdDeckLinkConfigRec2020Output = /* 'rec2' */ 0x72656332, // Ensure output is Rec.2020 colorspace + bmdDeckLinkConfigQuadLinkSDIVideoOutputSquareDivisionSplit = /* 'SDQS' */ 0x53445153, + bmdDeckLinkConfigOutput1080pAsPsF = /* 'pfpr' */ 0x70667072, /* Video Output Integers */ - bmdDeckLinkConfigVideoOutputConnection = 'vocn', - bmdDeckLinkConfigVideoOutputConversionMode = 'vocm', - bmdDeckLinkConfigAnalogVideoOutputFlags = 'avof', - bmdDeckLinkConfigReferenceInputTimingOffset = 'glot', - bmdDeckLinkConfigVideoOutputIdleOperation = 'voio', - bmdDeckLinkConfigDefaultVideoOutputMode = 'dvom', - bmdDeckLinkConfigDefaultVideoOutputModeFlags = 'dvof', - bmdDeckLinkConfigSDIOutputLinkConfiguration = 'solc', + bmdDeckLinkConfigVideoOutputConnection = /* 'vocn' */ 0x766F636E, + bmdDeckLinkConfigVideoOutputConversionMode = /* 'vocm' */ 0x766F636D, + bmdDeckLinkConfigAnalogVideoOutputFlags = /* 'avof' */ 0x61766F66, + bmdDeckLinkConfigReferenceInputTimingOffset = /* 'glot' */ 0x676C6F74, + bmdDeckLinkConfigVideoOutputIdleOperation = /* 'voio' */ 0x766F696F, + bmdDeckLinkConfigDefaultVideoOutputMode = /* 'dvom' */ 0x64766F6D, + bmdDeckLinkConfigDefaultVideoOutputModeFlags = /* 'dvof' */ 0x64766F66, + bmdDeckLinkConfigSDIOutputLinkConfiguration = /* 'solc' */ 0x736F6C63, + bmdDeckLinkConfigHDMITimecodePacking = /* 'htpk' */ 0x6874706B, + bmdDeckLinkConfigPlaybackGroup = /* 'plgr' */ 0x706C6772, /* Video Output Floats */ - bmdDeckLinkConfigVideoOutputComponentLumaGain = 'oclg', - bmdDeckLinkConfigVideoOutputComponentChromaBlueGain = 'occb', - bmdDeckLinkConfigVideoOutputComponentChromaRedGain = 'occr', - bmdDeckLinkConfigVideoOutputCompositeLumaGain = 'oilg', - bmdDeckLinkConfigVideoOutputCompositeChromaGain = 'oicg', - bmdDeckLinkConfigVideoOutputSVideoLumaGain = 'oslg', - bmdDeckLinkConfigVideoOutputSVideoChromaGain = 'oscg', + bmdDeckLinkConfigVideoOutputComponentLumaGain = /* 'oclg' */ 0x6F636C67, + bmdDeckLinkConfigVideoOutputComponentChromaBlueGain = /* 'occb' */ 0x6F636362, + bmdDeckLinkConfigVideoOutputComponentChromaRedGain = /* 'occr' */ 0x6F636372, + bmdDeckLinkConfigVideoOutputCompositeLumaGain = /* 'oilg' */ 0x6F696C67, + bmdDeckLinkConfigVideoOutputCompositeChromaGain = /* 'oicg' */ 0x6F696367, + bmdDeckLinkConfigVideoOutputSVideoLumaGain = /* 'oslg' */ 0x6F736C67, + bmdDeckLinkConfigVideoOutputSVideoChromaGain = /* 'oscg' */ 0x6F736367, /* Video Input Flags */ - bmdDeckLinkConfigVideoInputScanning = 'visc', // Applicable to H264 Pro Recorder only - bmdDeckLinkConfigUseDedicatedLTCInput = 'dltc', // Use timecode from LTC input instead of SDI stream - bmdDeckLinkConfigSDIInput3DPayloadOverride = '3dds', - - /* Video Input Flags */ - - bmdDeckLinkConfigCapture1080pAsPsF = 'cfpr', + bmdDeckLinkConfigVideoInputScanning = /* 'visc' */ 0x76697363, // Applicable to H264 Pro Recorder only + bmdDeckLinkConfigUseDedicatedLTCInput = /* 'dltc' */ 0x646C7463, // Use timecode from LTC input instead of SDI stream + bmdDeckLinkConfigSDIInput3DPayloadOverride = /* '3dds' */ 0x33646473, + bmdDeckLinkConfigCapture1080pAsPsF = /* 'cfpr' */ 0x63667072, /* Video Input Integers */ - bmdDeckLinkConfigVideoInputConnection = 'vicn', - bmdDeckLinkConfigAnalogVideoInputFlags = 'avif', - bmdDeckLinkConfigVideoInputConversionMode = 'vicm', - bmdDeckLinkConfig32PulldownSequenceInitialTimecodeFrame = 'pdif', - bmdDeckLinkConfigVANCSourceLine1Mapping = 'vsl1', - bmdDeckLinkConfigVANCSourceLine2Mapping = 'vsl2', - bmdDeckLinkConfigVANCSourceLine3Mapping = 'vsl3', - bmdDeckLinkConfigCapturePassThroughMode = 'cptm', + bmdDeckLinkConfigVideoInputConnection = /* 'vicn' */ 0x7669636E, + bmdDeckLinkConfigAnalogVideoInputFlags = /* 'avif' */ 0x61766966, + bmdDeckLinkConfigVideoInputConversionMode = /* 'vicm' */ 0x7669636D, + bmdDeckLinkConfig32PulldownSequenceInitialTimecodeFrame = /* 'pdif' */ 0x70646966, + bmdDeckLinkConfigVANCSourceLine1Mapping = /* 'vsl1' */ 0x76736C31, + bmdDeckLinkConfigVANCSourceLine2Mapping = /* 'vsl2' */ 0x76736C32, + bmdDeckLinkConfigVANCSourceLine3Mapping = /* 'vsl3' */ 0x76736C33, + bmdDeckLinkConfigCapturePassThroughMode = /* 'cptm' */ 0x6370746D, + bmdDeckLinkConfigCaptureGroup = /* 'cpgr' */ 0x63706772, /* Video Input Floats */ - bmdDeckLinkConfigVideoInputComponentLumaGain = 'iclg', - bmdDeckLinkConfigVideoInputComponentChromaBlueGain = 'iccb', - bmdDeckLinkConfigVideoInputComponentChromaRedGain = 'iccr', - bmdDeckLinkConfigVideoInputCompositeLumaGain = 'iilg', - bmdDeckLinkConfigVideoInputCompositeChromaGain = 'iicg', - bmdDeckLinkConfigVideoInputSVideoLumaGain = 'islg', - bmdDeckLinkConfigVideoInputSVideoChromaGain = 'iscg', + bmdDeckLinkConfigVideoInputComponentLumaGain = /* 'iclg' */ 0x69636C67, + bmdDeckLinkConfigVideoInputComponentChromaBlueGain = /* 'iccb' */ 0x69636362, + bmdDeckLinkConfigVideoInputComponentChromaRedGain = /* 'iccr' */ 0x69636372, + bmdDeckLinkConfigVideoInputCompositeLumaGain = /* 'iilg' */ 0x69696C67, + bmdDeckLinkConfigVideoInputCompositeChromaGain = /* 'iicg' */ 0x69696367, + bmdDeckLinkConfigVideoInputSVideoLumaGain = /* 'islg' */ 0x69736C67, + bmdDeckLinkConfigVideoInputSVideoChromaGain = /* 'iscg' */ 0x69736367, + + /* Keying Integers */ + + bmdDeckLinkConfigInternalKeyingAncillaryDataSource = /* 'ikas' */ 0x696B6173, /* Audio Input Flags */ - bmdDeckLinkConfigMicrophonePhantomPower = 'mphp', + bmdDeckLinkConfigMicrophonePhantomPower = /* 'mphp' */ 0x6D706870, /* Audio Input Integers */ - bmdDeckLinkConfigAudioInputConnection = 'aicn', + bmdDeckLinkConfigAudioInputConnection = /* 'aicn' */ 0x6169636E, /* Audio Input Floats */ - bmdDeckLinkConfigAnalogAudioInputScaleChannel1 = 'ais1', - bmdDeckLinkConfigAnalogAudioInputScaleChannel2 = 'ais2', - bmdDeckLinkConfigAnalogAudioInputScaleChannel3 = 'ais3', - bmdDeckLinkConfigAnalogAudioInputScaleChannel4 = 'ais4', - bmdDeckLinkConfigDigitalAudioInputScale = 'dais', - bmdDeckLinkConfigMicrophoneInputGain = 'micg', + bmdDeckLinkConfigAnalogAudioInputScaleChannel1 = /* 'ais1' */ 0x61697331, + bmdDeckLinkConfigAnalogAudioInputScaleChannel2 = /* 'ais2' */ 0x61697332, + bmdDeckLinkConfigAnalogAudioInputScaleChannel3 = /* 'ais3' */ 0x61697333, + bmdDeckLinkConfigAnalogAudioInputScaleChannel4 = /* 'ais4' */ 0x61697334, + bmdDeckLinkConfigDigitalAudioInputScale = /* 'dais' */ 0x64616973, + bmdDeckLinkConfigMicrophoneInputGain = /* 'micg' */ 0x6D696367, /* Audio Output Integers */ - bmdDeckLinkConfigAudioOutputAESAnalogSwitch = 'aoaa', + bmdDeckLinkConfigAudioOutputAESAnalogSwitch = /* 'aoaa' */ 0x616F6161, /* Audio Output Floats */ - bmdDeckLinkConfigAnalogAudioOutputScaleChannel1 = 'aos1', - bmdDeckLinkConfigAnalogAudioOutputScaleChannel2 = 'aos2', - bmdDeckLinkConfigAnalogAudioOutputScaleChannel3 = 'aos3', - bmdDeckLinkConfigAnalogAudioOutputScaleChannel4 = 'aos4', - bmdDeckLinkConfigDigitalAudioOutputScale = 'daos', - bmdDeckLinkConfigHeadphoneVolume = 'hvol', + bmdDeckLinkConfigAnalogAudioOutputScaleChannel1 = /* 'aos1' */ 0x616F7331, + bmdDeckLinkConfigAnalogAudioOutputScaleChannel2 = /* 'aos2' */ 0x616F7332, + bmdDeckLinkConfigAnalogAudioOutputScaleChannel3 = /* 'aos3' */ 0x616F7333, + bmdDeckLinkConfigAnalogAudioOutputScaleChannel4 = /* 'aos4' */ 0x616F7334, + bmdDeckLinkConfigDigitalAudioOutputScale = /* 'daos' */ 0x64616F73, + bmdDeckLinkConfigHeadphoneVolume = /* 'hvol' */ 0x68766F6C, /* Device Information Strings */ - bmdDeckLinkConfigDeviceInformationLabel = 'dila', - bmdDeckLinkConfigDeviceInformationSerialNumber = 'disn', - bmdDeckLinkConfigDeviceInformationCompany = 'dico', - bmdDeckLinkConfigDeviceInformationPhone = 'diph', - bmdDeckLinkConfigDeviceInformationEmail = 'diem', - bmdDeckLinkConfigDeviceInformationDate = 'dida', + bmdDeckLinkConfigDeviceInformationLabel = /* 'dila' */ 0x64696C61, + bmdDeckLinkConfigDeviceInformationSerialNumber = /* 'disn' */ 0x6469736E, + bmdDeckLinkConfigDeviceInformationCompany = /* 'dico' */ 0x6469636F, + bmdDeckLinkConfigDeviceInformationPhone = /* 'diph' */ 0x64697068, + bmdDeckLinkConfigDeviceInformationEmail = /* 'diem' */ 0x6469656D, + bmdDeckLinkConfigDeviceInformationDate = /* 'dida' */ 0x64696461, /* Deck Control Integers */ - bmdDeckLinkConfigDeckControlConnection = 'dcco' + bmdDeckLinkConfigDeckControlConnection = /* 'dcco' */ 0x6463636F }; /* Enum BMDDeckLinkEncoderConfigurationID - DeckLink Encoder Configuration ID */ @@ -188,27 +190,29 @@ enum _BMDDeckLinkEncoderConfigurationID { /* Video Encoder Integers */ - bmdDeckLinkEncoderConfigPreferredBitDepth = 'epbr', - bmdDeckLinkEncoderConfigFrameCodingMode = 'efcm', + bmdDeckLinkEncoderConfigPreferredBitDepth = /* 'epbr' */ 0x65706272, + bmdDeckLinkEncoderConfigFrameCodingMode = /* 'efcm' */ 0x6566636D, /* HEVC/H.265 Encoder Integers */ - bmdDeckLinkEncoderConfigH265TargetBitrate = 'htbr', + bmdDeckLinkEncoderConfigH265TargetBitrate = /* 'htbr' */ 0x68746272, /* DNxHR/DNxHD Compression ID */ - bmdDeckLinkEncoderConfigDNxHRCompressionID = 'dcid', + bmdDeckLinkEncoderConfigDNxHRCompressionID = /* 'dcid' */ 0x64636964, /* DNxHR/DNxHD Level */ - bmdDeckLinkEncoderConfigDNxHRLevel = 'dlev', + bmdDeckLinkEncoderConfigDNxHRLevel = /* 'dlev' */ 0x646C6576, /* Encoded Sample Decriptions */ - bmdDeckLinkEncoderConfigMPEG4SampleDescription = 'stsE', // Full MPEG4 sample description (aka SampleEntry of an 'stsd' atom-box). Useful for MediaFoundation, QuickTime, MKV and more - bmdDeckLinkEncoderConfigMPEG4CodecSpecificDesc = 'esds' // Sample description extensions only (atom stream, each with size and fourCC header). Useful for AVFoundation, VideoToolbox, MKV and more + bmdDeckLinkEncoderConfigMPEG4SampleDescription = /* 'stsE' */ 0x73747345, // Full MPEG4 sample description (aka SampleEntry of an 'stsd' atom-box). Useful for MediaFoundation, QuickTime, MKV and more + bmdDeckLinkEncoderConfigMPEG4CodecSpecificDesc = /* 'esds' */ 0x65736473 // Sample description extensions only (atom stream, each with size and fourCC header). Useful for AVFoundation, VideoToolbox, MKV and more }; +#if defined(__cplusplus) + // Forward Declarations class IDeckLinkConfiguration; @@ -220,13 +224,13 @@ class BMD_PUBLIC IDeckLinkConfiguration : public IUnknown { public: virtual HRESULT SetFlag (/* in */ BMDDeckLinkConfigurationID cfgID, /* in */ bool value) = 0; - virtual HRESULT GetFlag (/* in */ BMDDeckLinkConfigurationID cfgID, /* out */ bool *value) = 0; + virtual HRESULT GetFlag (/* in */ BMDDeckLinkConfigurationID cfgID, /* out */ bool* value) = 0; virtual HRESULT SetInt (/* in */ BMDDeckLinkConfigurationID cfgID, /* in */ int64_t value) = 0; - virtual HRESULT GetInt (/* in */ BMDDeckLinkConfigurationID cfgID, /* out */ int64_t *value) = 0; + virtual HRESULT GetInt (/* in */ BMDDeckLinkConfigurationID cfgID, /* out */ int64_t* value) = 0; virtual HRESULT SetFloat (/* in */ BMDDeckLinkConfigurationID cfgID, /* in */ double value) = 0; - virtual HRESULT GetFloat (/* in */ BMDDeckLinkConfigurationID cfgID, /* out */ double *value) = 0; + virtual HRESULT GetFloat (/* in */ BMDDeckLinkConfigurationID cfgID, /* out */ double* value) = 0; virtual HRESULT SetString (/* in */ BMDDeckLinkConfigurationID cfgID, /* in */ CFStringRef value) = 0; - virtual HRESULT GetString (/* in */ BMDDeckLinkConfigurationID cfgID, /* out */ CFStringRef *value) = 0; + virtual HRESULT GetString (/* in */ BMDDeckLinkConfigurationID cfgID, /* out */ CFStringRef* value) = 0; virtual HRESULT WriteConfigurationToPreferences (void) = 0; protected: @@ -239,14 +243,14 @@ class BMD_PUBLIC IDeckLinkEncoderConfiguration : public IUnknown { public: virtual HRESULT SetFlag (/* in */ BMDDeckLinkEncoderConfigurationID cfgID, /* in */ bool value) = 0; - virtual HRESULT GetFlag (/* in */ BMDDeckLinkEncoderConfigurationID cfgID, /* out */ bool *value) = 0; + virtual HRESULT GetFlag (/* in */ BMDDeckLinkEncoderConfigurationID cfgID, /* out */ bool* value) = 0; virtual HRESULT SetInt (/* in */ BMDDeckLinkEncoderConfigurationID cfgID, /* in */ int64_t value) = 0; - virtual HRESULT GetInt (/* in */ BMDDeckLinkEncoderConfigurationID cfgID, /* out */ int64_t *value) = 0; + virtual HRESULT GetInt (/* in */ BMDDeckLinkEncoderConfigurationID cfgID, /* out */ int64_t* value) = 0; virtual HRESULT SetFloat (/* in */ BMDDeckLinkEncoderConfigurationID cfgID, /* in */ double value) = 0; - virtual HRESULT GetFloat (/* in */ BMDDeckLinkEncoderConfigurationID cfgID, /* out */ double *value) = 0; + virtual HRESULT GetFloat (/* in */ BMDDeckLinkEncoderConfigurationID cfgID, /* out */ double* value) = 0; virtual HRESULT SetString (/* in */ BMDDeckLinkEncoderConfigurationID cfgID, /* in */ CFStringRef value) = 0; - virtual HRESULT GetString (/* in */ BMDDeckLinkEncoderConfigurationID cfgID, /* out */ CFStringRef *value) = 0; - virtual HRESULT GetBytes (/* in */ BMDDeckLinkEncoderConfigurationID cfgID, /* out */ void *buffer /* optional */, /* in, out */ uint32_t *bufferSize) = 0; + virtual HRESULT GetString (/* in */ BMDDeckLinkEncoderConfigurationID cfgID, /* out */ CFStringRef* value) = 0; + virtual HRESULT GetBytes (/* in */ BMDDeckLinkEncoderConfigurationID cfgID, /* out */ void* buffer /* optional */, /* in, out */ uint32_t* bufferSize) = 0; protected: virtual ~IDeckLinkEncoderConfiguration () {} // call Release method to drop reference count @@ -259,5 +263,5 @@ extern "C" { } - +#endif /* defined(__cplusplus) */ #endif /* defined(BMD_DECKLINKAPICONFIGURATION_H) */ diff --git a/plugins/decklink/mac/decklink-sdk/DeckLinkAPIConfiguration_v10_11.h b/plugins/decklink/mac/decklink-sdk/DeckLinkAPIConfiguration_v10_11.h new file mode 100644 index 0000000..a50a4e4 --- /dev/null +++ b/plugins/decklink/mac/decklink-sdk/DeckLinkAPIConfiguration_v10_11.h @@ -0,0 +1,71 @@ +/* -LICENSE-START- +** Copyright (c) 2017 Blackmagic Design +** +** Permission is hereby granted, free of charge, to any person or organization +** obtaining a copy of the software and accompanying documentation covered by +** this license (the "Software") to use, reproduce, display, distribute, +** execute, and transmit the Software, and to prepare derivative works of the +** Software, and to permit third-parties to whom the Software is furnished to +** do so, all subject to the following: +** +** The copyright notices in the Software and this entire statement, including +** the above license grant, this restriction and the following disclaimer, +** must be included in all copies of the Software, in whole or in part, and +** all derivative works of the Software, unless such copies or derivative +** works are solely in the form of machine-executable object code generated by +** a source language processor. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +** SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +** FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +** DEALINGS IN THE SOFTWARE. +** -LICENSE-END- +*/ + +#ifndef BMD_DECKLINKAPICONFIGURATION_v10_11_H +#define BMD_DECKLINKAPICONFIGURATION_v10_11_H + +#include "DeckLinkAPIConfiguration.h" + +// Interface ID Declarations + +BMD_CONST REFIID IID_IDeckLinkConfiguration_v10_11 = /* EF90380B-4AE5-4346-9077-E288E149F129 */ {0xEF,0x90,0x38,0x0B,0x4A,0xE5,0x43,0x46,0x90,0x77,0xE2,0x88,0xE1,0x49,0xF1,0x29}; + +/* Enum BMDDeckLinkConfigurationID_v10_11 - DeckLink Configuration ID */ + +typedef uint32_t BMDDeckLinkConfigurationID_v10_11; +enum _BMDDeckLinkConfigurationID_v10_11 { + + /* Video Input/Output Integers */ + + bmdDeckLinkConfigDuplexMode_v10_11 = 'dupx', +}; + +// Forward Declarations + +class IDeckLinkConfiguration_v10_11; + +/* Interface IDeckLinkConfiguration_v10_11 - DeckLink Configuration interface */ + +class IDeckLinkConfiguration_v10_11 : public IUnknown +{ +public: + virtual HRESULT SetFlag (/* in */ BMDDeckLinkConfigurationID cfgID, /* in */ bool value) = 0; + virtual HRESULT GetFlag (/* in */ BMDDeckLinkConfigurationID cfgID, /* out */ bool *value) = 0; + virtual HRESULT SetInt (/* in */ BMDDeckLinkConfigurationID cfgID, /* in */ int64_t value) = 0; + virtual HRESULT GetInt (/* in */ BMDDeckLinkConfigurationID cfgID, /* out */ int64_t *value) = 0; + virtual HRESULT SetFloat (/* in */ BMDDeckLinkConfigurationID cfgID, /* in */ double value) = 0; + virtual HRESULT GetFloat (/* in */ BMDDeckLinkConfigurationID cfgID, /* out */ double *value) = 0; + virtual HRESULT SetString (/* in */ BMDDeckLinkConfigurationID cfgID, /* in */ CFStringRef value) = 0; + virtual HRESULT GetString (/* in */ BMDDeckLinkConfigurationID cfgID, /* out */ CFStringRef *value) = 0; + virtual HRESULT WriteConfigurationToPreferences (void) = 0; + +protected: + virtual ~IDeckLinkConfiguration_v10_11 () {} // call Release method to drop reference count +}; + + +#endif /* defined(BMD_DECKLINKAPICONFIGURATION_v10_11_H) */ diff --git a/plugins/decklink/mac/decklink-sdk/DeckLinkAPIDeckControl.h b/plugins/decklink/mac/decklink-sdk/DeckLinkAPIDeckControl.h index b1b7797..fa9c17e 100644 --- a/plugins/decklink/mac/decklink-sdk/DeckLinkAPIDeckControl.h +++ b/plugins/decklink/mac/decklink-sdk/DeckLinkAPIDeckControl.h @@ -1,5 +1,5 @@ /* -LICENSE-START- -** Copyright (c) 2018 Blackmagic Design +** Copyright (c) 2020 Blackmagic Design ** ** Permission is hereby granted, free of charge, to any person or organization ** obtaining a copy of the software and accompanying documentation covered by @@ -7,14 +7,14 @@ ** execute, and transmit the Software, and to prepare derivative works of the ** Software, and to permit third-parties to whom the Software is furnished to ** do so, all subject to the following: -** +** ** The copyright notices in the Software and this entire statement, including ** the above license grant, this restriction and the following disclaimer, ** must be included in all copies of the Software, in whole or in part, and ** all derivative works of the Software, unless such copies or derivative ** works are solely in the form of machine-executable object code generated by ** a source language processor. -** +** ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT @@ -46,49 +46,49 @@ // Interface ID Declarations -BMD_CONST REFIID IID_IDeckLinkDeckControlStatusCallback = /* 53436FFB-B434-4906-BADC-AE3060FFE8EF */ {0x53,0x43,0x6F,0xFB,0xB4,0x34,0x49,0x06,0xBA,0xDC,0xAE,0x30,0x60,0xFF,0xE8,0xEF}; -BMD_CONST REFIID IID_IDeckLinkDeckControl = /* 8E1C3ACE-19C7-4E00-8B92-D80431D958BE */ {0x8E,0x1C,0x3A,0xCE,0x19,0xC7,0x4E,0x00,0x8B,0x92,0xD8,0x04,0x31,0xD9,0x58,0xBE}; +BMD_CONST REFIID IID_IDeckLinkDeckControlStatusCallback = /* 53436FFB-B434-4906-BADC-AE3060FFE8EF */ { 0x53,0x43,0x6F,0xFB,0xB4,0x34,0x49,0x06,0xBA,0xDC,0xAE,0x30,0x60,0xFF,0xE8,0xEF }; +BMD_CONST REFIID IID_IDeckLinkDeckControl = /* 8E1C3ACE-19C7-4E00-8B92-D80431D958BE */ { 0x8E,0x1C,0x3A,0xCE,0x19,0xC7,0x4E,0x00,0x8B,0x92,0xD8,0x04,0x31,0xD9,0x58,0xBE }; /* Enum BMDDeckControlMode - DeckControl mode */ typedef uint32_t BMDDeckControlMode; enum _BMDDeckControlMode { - bmdDeckControlNotOpened = 'ntop', - bmdDeckControlVTRControlMode = 'vtrc', - bmdDeckControlExportMode = 'expm', - bmdDeckControlCaptureMode = 'capm' + bmdDeckControlNotOpened = /* 'ntop' */ 0x6E746F70, + bmdDeckControlVTRControlMode = /* 'vtrc' */ 0x76747263, + bmdDeckControlExportMode = /* 'expm' */ 0x6578706D, + bmdDeckControlCaptureMode = /* 'capm' */ 0x6361706D }; /* Enum BMDDeckControlEvent - DeckControl event */ typedef uint32_t BMDDeckControlEvent; enum _BMDDeckControlEvent { - bmdDeckControlAbortedEvent = 'abte', // This event is triggered when a capture or edit-to-tape operation is aborted. + bmdDeckControlAbortedEvent = /* 'abte' */ 0x61627465, // This event is triggered when a capture or edit-to-tape operation is aborted. /* Export-To-Tape events */ - bmdDeckControlPrepareForExportEvent = 'pfee', // This event is triggered a few frames before reaching the in-point. IDeckLinkInput::StartScheduledPlayback() should be called at this point. - bmdDeckControlExportCompleteEvent = 'exce', // This event is triggered a few frames after reaching the out-point. At this point, it is safe to stop playback. + bmdDeckControlPrepareForExportEvent = /* 'pfee' */ 0x70666565, // This event is triggered a few frames before reaching the in-point. IDeckLinkInput::StartScheduledPlayback should be called at this point. + bmdDeckControlExportCompleteEvent = /* 'exce' */ 0x65786365, // This event is triggered a few frames after reaching the out-point. At this point, it is safe to stop playback. Upon reception of this event the deck's control mode is set back to bmdDeckControlVTRControlMode. /* Capture events */ - bmdDeckControlPrepareForCaptureEvent = 'pfce', // This event is triggered a few frames before reaching the in-point. The serial timecode attached to IDeckLinkVideoInputFrames is now valid. - bmdDeckControlCaptureCompleteEvent = 'ccev' // This event is triggered a few frames after reaching the out-point. + bmdDeckControlPrepareForCaptureEvent = /* 'pfce' */ 0x70666365, // This event is triggered a few frames before reaching the in-point. The serial timecode attached to IDeckLinkVideoInputFrames is now valid. + bmdDeckControlCaptureCompleteEvent = /* 'ccev' */ 0x63636576 // This event is triggered a few frames after reaching the out-point. Upon reception of this event the deck's control mode is set back to bmdDeckControlVTRControlMode. }; /* Enum BMDDeckControlVTRControlState - VTR Control state */ typedef uint32_t BMDDeckControlVTRControlState; enum _BMDDeckControlVTRControlState { - bmdDeckControlNotInVTRControlMode = 'nvcm', - bmdDeckControlVTRControlPlaying = 'vtrp', - bmdDeckControlVTRControlRecording = 'vtrr', - bmdDeckControlVTRControlStill = 'vtra', - bmdDeckControlVTRControlShuttleForward = 'vtsf', - bmdDeckControlVTRControlShuttleReverse = 'vtsr', - bmdDeckControlVTRControlJogForward = 'vtjf', - bmdDeckControlVTRControlJogReverse = 'vtjr', - bmdDeckControlVTRControlStopped = 'vtro' + bmdDeckControlNotInVTRControlMode = /* 'nvcm' */ 0x6E76636D, + bmdDeckControlVTRControlPlaying = /* 'vtrp' */ 0x76747270, + bmdDeckControlVTRControlRecording = /* 'vtrr' */ 0x76747272, + bmdDeckControlVTRControlStill = /* 'vtra' */ 0x76747261, + bmdDeckControlVTRControlShuttleForward = /* 'vtsf' */ 0x76747366, + bmdDeckControlVTRControlShuttleReverse = /* 'vtsr' */ 0x76747372, + bmdDeckControlVTRControlJogForward = /* 'vtjf' */ 0x76746A66, + bmdDeckControlVTRControlJogReverse = /* 'vtjr' */ 0x76746A72, + bmdDeckControlVTRControlStopped = /* 'vtro' */ 0x7674726F }; /* Enum BMDDeckControlStatusFlags - Deck Control status flags */ @@ -128,24 +128,26 @@ enum _BMDDeckControlExportModeOpsFlags { typedef uint32_t BMDDeckControlError; enum _BMDDeckControlError { - bmdDeckControlNoError = 'noer', - bmdDeckControlModeError = 'moer', - bmdDeckControlMissedInPointError = 'mier', - bmdDeckControlDeckTimeoutError = 'dter', - bmdDeckControlCommandFailedError = 'cfer', - bmdDeckControlDeviceAlreadyOpenedError = 'dalo', - bmdDeckControlFailedToOpenDeviceError = 'fder', - bmdDeckControlInLocalModeError = 'lmer', - bmdDeckControlEndOfTapeError = 'eter', - bmdDeckControlUserAbortError = 'uaer', - bmdDeckControlNoTapeInDeckError = 'nter', - bmdDeckControlNoVideoFromCardError = 'nvfc', - bmdDeckControlNoCommunicationError = 'ncom', - bmdDeckControlBufferTooSmallError = 'btsm', - bmdDeckControlBadChecksumError = 'chks', - bmdDeckControlUnknownError = 'uner' + bmdDeckControlNoError = /* 'noer' */ 0x6E6F6572, + bmdDeckControlModeError = /* 'moer' */ 0x6D6F6572, + bmdDeckControlMissedInPointError = /* 'mier' */ 0x6D696572, + bmdDeckControlDeckTimeoutError = /* 'dter' */ 0x64746572, + bmdDeckControlCommandFailedError = /* 'cfer' */ 0x63666572, + bmdDeckControlDeviceAlreadyOpenedError = /* 'dalo' */ 0x64616C6F, + bmdDeckControlFailedToOpenDeviceError = /* 'fder' */ 0x66646572, + bmdDeckControlInLocalModeError = /* 'lmer' */ 0x6C6D6572, + bmdDeckControlEndOfTapeError = /* 'eter' */ 0x65746572, + bmdDeckControlUserAbortError = /* 'uaer' */ 0x75616572, + bmdDeckControlNoTapeInDeckError = /* 'nter' */ 0x6E746572, + bmdDeckControlNoVideoFromCardError = /* 'nvfc' */ 0x6E766663, + bmdDeckControlNoCommunicationError = /* 'ncom' */ 0x6E636F6D, + bmdDeckControlBufferTooSmallError = /* 'btsm' */ 0x6274736D, + bmdDeckControlBadChecksumError = /* 'chks' */ 0x63686B73, + bmdDeckControlUnknownError = /* 'uner' */ 0x756E6572 }; +#if defined(__cplusplus) + // Forward Declarations class IDeckLinkDeckControlStatusCallback; @@ -170,39 +172,39 @@ protected: class BMD_PUBLIC IDeckLinkDeckControl : public IUnknown { public: - virtual HRESULT Open (/* in */ BMDTimeScale timeScale, /* in */ BMDTimeValue timeValue, /* in */ bool timecodeIsDropFrame, /* out */ BMDDeckControlError *error) = 0; + virtual HRESULT Open (/* in */ BMDTimeScale timeScale, /* in */ BMDTimeValue timeValue, /* in */ bool timecodeIsDropFrame, /* out */ BMDDeckControlError* error) = 0; virtual HRESULT Close (/* in */ bool standbyOn) = 0; - virtual HRESULT GetCurrentState (/* out */ BMDDeckControlMode *mode, /* out */ BMDDeckControlVTRControlState *vtrControlState, /* out */ BMDDeckControlStatusFlags *flags) = 0; + virtual HRESULT GetCurrentState (/* out */ BMDDeckControlMode* mode, /* out */ BMDDeckControlVTRControlState* vtrControlState, /* out */ BMDDeckControlStatusFlags* flags) = 0; virtual HRESULT SetStandby (/* in */ bool standbyOn) = 0; - virtual HRESULT SendCommand (/* in */ uint8_t *inBuffer, /* in */ uint32_t inBufferSize, /* out */ uint8_t *outBuffer, /* out */ uint32_t *outDataSize, /* in */ uint32_t outBufferSize, /* out */ BMDDeckControlError *error) = 0; - virtual HRESULT Play (/* out */ BMDDeckControlError *error) = 0; - virtual HRESULT Stop (/* out */ BMDDeckControlError *error) = 0; - virtual HRESULT TogglePlayStop (/* out */ BMDDeckControlError *error) = 0; - virtual HRESULT Eject (/* out */ BMDDeckControlError *error) = 0; - virtual HRESULT GoToTimecode (/* in */ BMDTimecodeBCD timecode, /* out */ BMDDeckControlError *error) = 0; - virtual HRESULT FastForward (/* in */ bool viewTape, /* out */ BMDDeckControlError *error) = 0; - virtual HRESULT Rewind (/* in */ bool viewTape, /* out */ BMDDeckControlError *error) = 0; - virtual HRESULT StepForward (/* out */ BMDDeckControlError *error) = 0; - virtual HRESULT StepBack (/* out */ BMDDeckControlError *error) = 0; - virtual HRESULT Jog (/* in */ double rate, /* out */ BMDDeckControlError *error) = 0; - virtual HRESULT Shuttle (/* in */ double rate, /* out */ BMDDeckControlError *error) = 0; - virtual HRESULT GetTimecodeString (/* out */ CFStringRef *currentTimeCode, /* out */ BMDDeckControlError *error) = 0; - virtual HRESULT GetTimecode (/* out */ IDeckLinkTimecode **currentTimecode, /* out */ BMDDeckControlError *error) = 0; - virtual HRESULT GetTimecodeBCD (/* out */ BMDTimecodeBCD *currentTimecode, /* out */ BMDDeckControlError *error) = 0; + virtual HRESULT SendCommand (/* in */ uint8_t* inBuffer, /* in */ uint32_t inBufferSize, /* out */ uint8_t* outBuffer, /* out */ uint32_t* outDataSize, /* in */ uint32_t outBufferSize, /* out */ BMDDeckControlError* error) = 0; + virtual HRESULT Play (/* out */ BMDDeckControlError* error) = 0; + virtual HRESULT Stop (/* out */ BMDDeckControlError* error) = 0; + virtual HRESULT TogglePlayStop (/* out */ BMDDeckControlError* error) = 0; + virtual HRESULT Eject (/* out */ BMDDeckControlError* error) = 0; + virtual HRESULT GoToTimecode (/* in */ BMDTimecodeBCD timecode, /* out */ BMDDeckControlError* error) = 0; + virtual HRESULT FastForward (/* in */ bool viewTape, /* out */ BMDDeckControlError* error) = 0; + virtual HRESULT Rewind (/* in */ bool viewTape, /* out */ BMDDeckControlError* error) = 0; + virtual HRESULT StepForward (/* out */ BMDDeckControlError* error) = 0; + virtual HRESULT StepBack (/* out */ BMDDeckControlError* error) = 0; + virtual HRESULT Jog (/* in */ double rate, /* out */ BMDDeckControlError* error) = 0; + virtual HRESULT Shuttle (/* in */ double rate, /* out */ BMDDeckControlError* error) = 0; + virtual HRESULT GetTimecodeString (/* out */ CFStringRef* currentTimeCode, /* out */ BMDDeckControlError* error) = 0; + virtual HRESULT GetTimecode (/* out */ IDeckLinkTimecode** currentTimecode, /* out */ BMDDeckControlError* error) = 0; + virtual HRESULT GetTimecodeBCD (/* out */ BMDTimecodeBCD* currentTimecode, /* out */ BMDDeckControlError* error) = 0; virtual HRESULT SetPreroll (/* in */ uint32_t prerollSeconds) = 0; - virtual HRESULT GetPreroll (/* out */ uint32_t *prerollSeconds) = 0; + virtual HRESULT GetPreroll (/* out */ uint32_t* prerollSeconds) = 0; virtual HRESULT SetExportOffset (/* in */ int32_t exportOffsetFields) = 0; - virtual HRESULT GetExportOffset (/* out */ int32_t *exportOffsetFields) = 0; - virtual HRESULT GetManualExportOffset (/* out */ int32_t *deckManualExportOffsetFields) = 0; + virtual HRESULT GetExportOffset (/* out */ int32_t* exportOffsetFields) = 0; + virtual HRESULT GetManualExportOffset (/* out */ int32_t* deckManualExportOffsetFields) = 0; virtual HRESULT SetCaptureOffset (/* in */ int32_t captureOffsetFields) = 0; - virtual HRESULT GetCaptureOffset (/* out */ int32_t *captureOffsetFields) = 0; - virtual HRESULT StartExport (/* in */ BMDTimecodeBCD inTimecode, /* in */ BMDTimecodeBCD outTimecode, /* in */ BMDDeckControlExportModeOpsFlags exportModeOps, /* out */ BMDDeckControlError *error) = 0; - virtual HRESULT StartCapture (/* in */ bool useVITC, /* in */ BMDTimecodeBCD inTimecode, /* in */ BMDTimecodeBCD outTimecode, /* out */ BMDDeckControlError *error) = 0; - virtual HRESULT GetDeviceID (/* out */ uint16_t *deviceId, /* out */ BMDDeckControlError *error) = 0; + virtual HRESULT GetCaptureOffset (/* out */ int32_t* captureOffsetFields) = 0; + virtual HRESULT StartExport (/* in */ BMDTimecodeBCD inTimecode, /* in */ BMDTimecodeBCD outTimecode, /* in */ BMDDeckControlExportModeOpsFlags exportModeOps, /* out */ BMDDeckControlError* error) = 0; + virtual HRESULT StartCapture (/* in */ bool useVITC, /* in */ BMDTimecodeBCD inTimecode, /* in */ BMDTimecodeBCD outTimecode, /* out */ BMDDeckControlError* error) = 0; + virtual HRESULT GetDeviceID (/* out */ uint16_t* deviceId, /* out */ BMDDeckControlError* error) = 0; virtual HRESULT Abort (void) = 0; - virtual HRESULT CrashRecordStart (/* out */ BMDDeckControlError *error) = 0; - virtual HRESULT CrashRecordStop (/* out */ BMDDeckControlError *error) = 0; - virtual HRESULT SetCallback (/* in */ IDeckLinkDeckControlStatusCallback *callback) = 0; + virtual HRESULT CrashRecordStart (/* out */ BMDDeckControlError* error) = 0; + virtual HRESULT CrashRecordStop (/* out */ BMDDeckControlError* error) = 0; + virtual HRESULT SetCallback (/* in */ IDeckLinkDeckControlStatusCallback* callback) = 0; protected: virtual ~IDeckLinkDeckControl () {} // call Release method to drop reference count @@ -215,5 +217,5 @@ extern "C" { } - +#endif /* defined(__cplusplus) */ #endif /* defined(BMD_DECKLINKAPIDECKCONTROL_H) */ diff --git a/plugins/decklink/mac/decklink-sdk/DeckLinkAPIDiscovery.h b/plugins/decklink/mac/decklink-sdk/DeckLinkAPIDiscovery.h index c8331ad..e03a29d 100644 --- a/plugins/decklink/mac/decklink-sdk/DeckLinkAPIDiscovery.h +++ b/plugins/decklink/mac/decklink-sdk/DeckLinkAPIDiscovery.h @@ -1,5 +1,5 @@ /* -LICENSE-START- -** Copyright (c) 2018 Blackmagic Design +** Copyright (c) 2020 Blackmagic Design ** ** Permission is hereby granted, free of charge, to any person or organization ** obtaining a copy of the software and accompanying documentation covered by @@ -7,14 +7,14 @@ ** execute, and transmit the Software, and to prepare derivative works of the ** Software, and to permit third-parties to whom the Software is furnished to ** do so, all subject to the following: -** +** ** The copyright notices in the Software and this entire statement, including ** the above license grant, this restriction and the following disclaimer, ** must be included in all copies of the Software, in whole or in part, and ** all derivative works of the Software, unless such copies or derivative ** works are solely in the form of machine-executable object code generated by ** a source language processor. -** +** ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT @@ -46,19 +46,21 @@ // Interface ID Declarations -BMD_CONST REFIID IID_IDeckLink = /* C418FBDD-0587-48ED-8FE5-640F0A14AF91 */ {0xC4,0x18,0xFB,0xDD,0x05,0x87,0x48,0xED,0x8F,0xE5,0x64,0x0F,0x0A,0x14,0xAF,0x91}; +BMD_CONST REFIID IID_IDeckLink = /* C418FBDD-0587-48ED-8FE5-640F0A14AF91 */ { 0xC4,0x18,0xFB,0xDD,0x05,0x87,0x48,0xED,0x8F,0xE5,0x64,0x0F,0x0A,0x14,0xAF,0x91 }; + +#if defined(__cplusplus) // Forward Declarations class IDeckLink; -/* Interface IDeckLink - represents a DeckLink device */ +/* Interface IDeckLink - Represents a DeckLink device */ class BMD_PUBLIC IDeckLink : public IUnknown { public: - virtual HRESULT GetModelName (/* out */ CFStringRef *modelName) = 0; - virtual HRESULT GetDisplayName (/* out */ CFStringRef *displayName) = 0; + virtual HRESULT GetModelName (/* out */ CFStringRef* modelName) = 0; + virtual HRESULT GetDisplayName (/* out */ CFStringRef* displayName) = 0; protected: virtual ~IDeckLink () {} // call Release method to drop reference count @@ -71,5 +73,5 @@ extern "C" { } - +#endif /* defined(__cplusplus) */ #endif /* defined(BMD_DECKLINKAPIDISCOVERY_H) */ diff --git a/plugins/decklink/mac/decklink-sdk/DeckLinkAPIDispatch.cpp b/plugins/decklink/mac/decklink-sdk/DeckLinkAPIDispatch.cpp index 7bb93ce..afce428 100644 --- a/plugins/decklink/mac/decklink-sdk/DeckLinkAPIDispatch.cpp +++ b/plugins/decklink/mac/decklink-sdk/DeckLinkAPIDispatch.cpp @@ -65,12 +65,12 @@ static void InitDeckLinkAPI (void) gDeckLinkAPIBundleRef = CFBundleCreate(kCFAllocatorDefault, bundleURL); if (gDeckLinkAPIBundleRef != NULL) { - gCreateIteratorFunc = (CreateIteratorFunc)CFBundleGetFunctionPointerForName(gDeckLinkAPIBundleRef, CFSTR("CreateDeckLinkIteratorInstance_0003")); + gCreateIteratorFunc = (CreateIteratorFunc)CFBundleGetFunctionPointerForName(gDeckLinkAPIBundleRef, CFSTR("CreateDeckLinkIteratorInstance_0004")); gCreateAPIInformationFunc = (CreateAPIInformationFunc)CFBundleGetFunctionPointerForName(gDeckLinkAPIBundleRef, CFSTR("CreateDeckLinkAPIInformationInstance_0001")); gCreateOpenGLPreviewFunc = (CreateOpenGLScreenPreviewHelperFunc)CFBundleGetFunctionPointerForName(gDeckLinkAPIBundleRef, CFSTR("CreateOpenGLScreenPreviewHelper_0001")); gCreateCocoaPreviewFunc = (CreateCocoaScreenPreviewFunc)CFBundleGetFunctionPointerForName(gDeckLinkAPIBundleRef, CFSTR("CreateCocoaScreenPreview_0001")); gCreateVideoConversionFunc = (CreateVideoConversionInstanceFunc)CFBundleGetFunctionPointerForName(gDeckLinkAPIBundleRef, CFSTR("CreateVideoConversionInstance_0001")); - gCreateDeckLinkDiscoveryFunc = (CreateDeckLinkDiscoveryInstanceFunc)CFBundleGetFunctionPointerForName(gDeckLinkAPIBundleRef, CFSTR("CreateDeckLinkDiscoveryInstance_0002")); + gCreateDeckLinkDiscoveryFunc = (CreateDeckLinkDiscoveryInstanceFunc)CFBundleGetFunctionPointerForName(gDeckLinkAPIBundleRef, CFSTR("CreateDeckLinkDiscoveryInstance_0003")); gCreateVideoFrameAncillaryPacketsFunc = (CreateVideoFrameAncillaryPacketsInstanceFunc)CFBundleGetFunctionPointerForName(gDeckLinkAPIBundleRef, CFSTR("CreateVideoFrameAncillaryPacketsInstance_0001")); } CFRelease(bundleURL); diff --git a/plugins/decklink/mac/decklink-sdk/DeckLinkAPIDispatch_v10_11.cpp b/plugins/decklink/mac/decklink-sdk/DeckLinkAPIDispatch_v10_11.cpp new file mode 100644 index 0000000..f5b528f --- /dev/null +++ b/plugins/decklink/mac/decklink-sdk/DeckLinkAPIDispatch_v10_11.cpp @@ -0,0 +1,206 @@ +/* -LICENSE-START- +** Copyright (c) 2019 Blackmagic Design +** +** Permission is hereby granted, free of charge, to any person or organization +** obtaining a copy of the software and accompanying documentation covered by +** this license (the "Software") to use, reproduce, display, distribute, +** execute, and transmit the Software, and to prepare derivative works of the +** Software, and to permit third-parties to whom the Software is furnished to +** do so, all subject to the following: +** +** The copyright notices in the Software and this entire statement, including +** the above license grant, this restriction and the following disclaimer, +** must be included in all copies of the Software, in whole or in part, and +** all derivative works of the Software, unless such copies or derivative +** works are solely in the form of machine-executable object code generated by +** a source language processor. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +** SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +** FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +** DEALINGS IN THE SOFTWARE. +** -LICENSE-END- +*/ +/* DeckLinkAPIDispatch.cpp */ + +#include "DeckLinkAPI_v10_11.h" +#include + +#if BLACKMAGIC_DECKLINK_API_MAGIC != 1 + #error The DeckLink API version of DeckLinkAPIDispatch.cpp is not the same version as DeckLinkAPI.h +#endif + +#define kDeckLinkAPI_BundlePath "/Library/Frameworks/DeckLinkAPI.framework" + + +typedef IDeckLinkIterator* (*CreateIteratorFunc)(void); +typedef IDeckLinkAPIInformation* (*CreateAPIInformationFunc)(void); +typedef IDeckLinkGLScreenPreviewHelper* (*CreateOpenGLScreenPreviewHelperFunc)(void); +typedef IDeckLinkCocoaScreenPreviewCallback* (*CreateCocoaScreenPreviewFunc)(void*); +typedef IDeckLinkVideoConversion* (*CreateVideoConversionInstanceFunc)(void); +typedef IDeckLinkDiscovery* (*CreateDeckLinkDiscoveryInstanceFunc)(void); +typedef IDeckLinkVideoFrameAncillaryPackets* (*CreateVideoFrameAncillaryPacketsInstanceFunc)(void); + +static pthread_once_t gDeckLinkOnceControl = PTHREAD_ONCE_INIT; +static CFBundleRef gDeckLinkAPIBundleRef = NULL; +static CreateIteratorFunc gCreateIteratorFunc = NULL; +static CreateAPIInformationFunc gCreateAPIInformationFunc = NULL; +static CreateOpenGLScreenPreviewHelperFunc gCreateOpenGLPreviewFunc = NULL; +static CreateCocoaScreenPreviewFunc gCreateCocoaPreviewFunc = NULL; +static CreateVideoConversionInstanceFunc gCreateVideoConversionFunc = NULL; +static CreateDeckLinkDiscoveryInstanceFunc gCreateDeckLinkDiscoveryFunc= NULL; +static CreateVideoFrameAncillaryPacketsInstanceFunc gCreateVideoFrameAncillaryPacketsFunc = NULL; + + +static void InitDeckLinkAPI (void) +{ + CFURLRef bundleURL; + + bundleURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, CFSTR(kDeckLinkAPI_BundlePath), kCFURLPOSIXPathStyle, true); + if (bundleURL != NULL) + { + gDeckLinkAPIBundleRef = CFBundleCreate(kCFAllocatorDefault, bundleURL); + if (gDeckLinkAPIBundleRef != NULL) + { + gCreateIteratorFunc = (CreateIteratorFunc)CFBundleGetFunctionPointerForName(gDeckLinkAPIBundleRef, CFSTR("CreateDeckLinkIteratorInstance_0003")); + gCreateAPIInformationFunc = (CreateAPIInformationFunc)CFBundleGetFunctionPointerForName(gDeckLinkAPIBundleRef, CFSTR("CreateDeckLinkAPIInformationInstance_0001")); + gCreateOpenGLPreviewFunc = (CreateOpenGLScreenPreviewHelperFunc)CFBundleGetFunctionPointerForName(gDeckLinkAPIBundleRef, CFSTR("CreateOpenGLScreenPreviewHelper_0001")); + gCreateCocoaPreviewFunc = (CreateCocoaScreenPreviewFunc)CFBundleGetFunctionPointerForName(gDeckLinkAPIBundleRef, CFSTR("CreateCocoaScreenPreview_0001")); + gCreateVideoConversionFunc = (CreateVideoConversionInstanceFunc)CFBundleGetFunctionPointerForName(gDeckLinkAPIBundleRef, CFSTR("CreateVideoConversionInstance_0001")); + gCreateDeckLinkDiscoveryFunc = (CreateDeckLinkDiscoveryInstanceFunc)CFBundleGetFunctionPointerForName(gDeckLinkAPIBundleRef, CFSTR("CreateDeckLinkDiscoveryInstance_0002")); + gCreateVideoFrameAncillaryPacketsFunc = (CreateVideoFrameAncillaryPacketsInstanceFunc)CFBundleGetFunctionPointerForName(gDeckLinkAPIBundleRef, CFSTR("CreateVideoFrameAncillaryPacketsInstance_0001")); + } + CFRelease(bundleURL); + } +} + +bool IsDeckLinkAPIPresent_v10_11 (void) +{ + // If the DeckLink API bundle was successfully loaded, return this knowledge to the caller + if (gDeckLinkAPIBundleRef != NULL) + return true; + + return false; +} + +IDeckLinkIterator* CreateDeckLinkIteratorInstance_v10_11 (void) +{ + pthread_once(&gDeckLinkOnceControl, InitDeckLinkAPI); + + if (gCreateIteratorFunc == NULL) + return NULL; + + return gCreateIteratorFunc(); +} + +IDeckLinkAPIInformation* CreateDeckLinkAPIInformationInstance_v10_11 (void) +{ + pthread_once(&gDeckLinkOnceControl, InitDeckLinkAPI); + + if (gCreateAPIInformationFunc == NULL) + return NULL; + + return gCreateAPIInformationFunc(); +} + +IDeckLinkGLScreenPreviewHelper* CreateOpenGLScreenPreviewHelper_v10_11 (void) +{ + pthread_once(&gDeckLinkOnceControl, InitDeckLinkAPI); + + if (gCreateOpenGLPreviewFunc == NULL) + return NULL; + + return gCreateOpenGLPreviewFunc(); +} + +IDeckLinkCocoaScreenPreviewCallback* CreateCocoaScreenPreview_v10_11 (void* parentView) +{ + pthread_once(&gDeckLinkOnceControl, InitDeckLinkAPI); + + if (gCreateCocoaPreviewFunc == NULL) + return NULL; + + return gCreateCocoaPreviewFunc(parentView); +} + +IDeckLinkVideoConversion* CreateVideoConversionInstance_v10_11 (void) +{ + pthread_once(&gDeckLinkOnceControl, InitDeckLinkAPI); + + if (gCreateVideoConversionFunc == NULL) + return NULL; + + return gCreateVideoConversionFunc(); +} + +IDeckLinkDiscovery* CreateDeckLinkDiscoveryInstance_v10_11 (void) +{ + pthread_once(&gDeckLinkOnceControl, InitDeckLinkAPI); + + if (gCreateDeckLinkDiscoveryFunc == NULL) + return NULL; + + return gCreateDeckLinkDiscoveryFunc(); +} + +IDeckLinkVideoFrameAncillaryPackets* CreateVideoFrameAncillaryPacketsInstance_v10_11 (void) +{ + pthread_once(&gDeckLinkOnceControl, InitDeckLinkAPI); + + if (gCreateVideoFrameAncillaryPacketsFunc == NULL) + return NULL; + + return gCreateVideoFrameAncillaryPacketsFunc(); +} + + +#define kBMDStreamingAPI_BundlePath "/Library/Application Support/Blackmagic Design/Streaming/BMDStreamingAPI.bundle" + +typedef IBMDStreamingDiscovery* (*CreateDiscoveryFunc)(void); +typedef IBMDStreamingH264NALParser* (*CreateNALParserFunc)(void); + +static pthread_once_t gBMDStreamingOnceControl = PTHREAD_ONCE_INIT; +static CFBundleRef gBMDStreamingAPIBundleRef = NULL; +static CreateDiscoveryFunc gCreateDiscoveryFunc = NULL; +static CreateNALParserFunc gCreateNALParserFunc = NULL; + +static void InitBMDStreamingAPI(void) +{ + CFURLRef bundleURL; + + bundleURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, CFSTR(kBMDStreamingAPI_BundlePath), kCFURLPOSIXPathStyle, true); + if (bundleURL != NULL) + { + gBMDStreamingAPIBundleRef = CFBundleCreate(kCFAllocatorDefault, bundleURL); + if (gBMDStreamingAPIBundleRef != NULL) + { + gCreateDiscoveryFunc = (CreateDiscoveryFunc)CFBundleGetFunctionPointerForName(gBMDStreamingAPIBundleRef, CFSTR("CreateBMDStreamingDiscoveryInstance_0002")); + gCreateNALParserFunc = (CreateNALParserFunc)CFBundleGetFunctionPointerForName(gBMDStreamingAPIBundleRef, CFSTR("CreateBMDStreamingH264NALParser_0001")); + } + + CFRelease(bundleURL); + } +} + +IBMDStreamingDiscovery* CreateBMDStreamingDiscoveryInstance_v10_11() +{ + pthread_once(&gBMDStreamingOnceControl, InitBMDStreamingAPI); + + if (gCreateDiscoveryFunc == NULL) + return NULL; + + return gCreateDiscoveryFunc(); +} + +IBMDStreamingH264NALParser* CreateBMDStreamingH264NALParser_v10_11() +{ + pthread_once(&gBMDStreamingOnceControl, InitBMDStreamingAPI); + + if (gCreateNALParserFunc == NULL) + return NULL; + + return gCreateNALParserFunc(); +} diff --git a/plugins/decklink/mac/decklink-sdk/DeckLinkAPIModes.h b/plugins/decklink/mac/decklink-sdk/DeckLinkAPIModes.h index 9a242e0..97fd4b0 100644 --- a/plugins/decklink/mac/decklink-sdk/DeckLinkAPIModes.h +++ b/plugins/decklink/mac/decklink-sdk/DeckLinkAPIModes.h @@ -1,5 +1,5 @@ /* -LICENSE-START- -** Copyright (c) 2018 Blackmagic Design +** Copyright (c) 2020 Blackmagic Design ** ** Permission is hereby granted, free of charge, to any person or organization ** obtaining a copy of the software and accompanying documentation covered by @@ -7,14 +7,14 @@ ** execute, and transmit the Software, and to prepare derivative works of the ** Software, and to permit third-parties to whom the Software is furnished to ** do so, all subject to the following: -** +** ** The copyright notices in the Software and this entire statement, including ** the above license grant, this restriction and the following disclaimer, ** must be included in all copies of the Software, in whole or in part, and ** all derivative works of the Software, unless such copies or derivative ** works are solely in the form of machine-executable object code generated by ** a source language processor. -** +** ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT @@ -46,147 +46,189 @@ // Interface ID Declarations -BMD_CONST REFIID IID_IDeckLinkDisplayModeIterator = /* 9C88499F-F601-4021-B80B-032E4EB41C35 */ {0x9C,0x88,0x49,0x9F,0xF6,0x01,0x40,0x21,0xB8,0x0B,0x03,0x2E,0x4E,0xB4,0x1C,0x35}; -BMD_CONST REFIID IID_IDeckLinkDisplayMode = /* 3EB2C1AB-0A3D-4523-A3AD-F40D7FB14E78 */ {0x3E,0xB2,0xC1,0xAB,0x0A,0x3D,0x45,0x23,0xA3,0xAD,0xF4,0x0D,0x7F,0xB1,0x4E,0x78}; +BMD_CONST REFIID IID_IDeckLinkDisplayModeIterator = /* 9C88499F-F601-4021-B80B-032E4EB41C35 */ { 0x9C,0x88,0x49,0x9F,0xF6,0x01,0x40,0x21,0xB8,0x0B,0x03,0x2E,0x4E,0xB4,0x1C,0x35 }; +BMD_CONST REFIID IID_IDeckLinkDisplayMode = /* 3EB2C1AB-0A3D-4523-A3AD-F40D7FB14E78 */ { 0x3E,0xB2,0xC1,0xAB,0x0A,0x3D,0x45,0x23,0xA3,0xAD,0xF4,0x0D,0x7F,0xB1,0x4E,0x78 }; -/* Enum BMDDisplayMode - Video display modes */ +/* Enum BMDDisplayMode - BMDDisplayMode enumerates the video modes supported. */ typedef uint32_t BMDDisplayMode; enum _BMDDisplayMode { /* SD Modes */ - bmdModeNTSC = 'ntsc', - bmdModeNTSC2398 = 'nt23', // 3:2 pulldown - bmdModePAL = 'pal ', - bmdModeNTSCp = 'ntsp', - bmdModePALp = 'palp', + bmdModeNTSC = /* 'ntsc' */ 0x6E747363, + bmdModeNTSC2398 = /* 'nt23' */ 0x6E743233, // 3:2 pulldown + bmdModePAL = /* 'pal ' */ 0x70616C20, + bmdModeNTSCp = /* 'ntsp' */ 0x6E747370, + bmdModePALp = /* 'palp' */ 0x70616C70, /* HD 1080 Modes */ - bmdModeHD1080p2398 = '23ps', - bmdModeHD1080p24 = '24ps', - bmdModeHD1080p25 = 'Hp25', - bmdModeHD1080p2997 = 'Hp29', - bmdModeHD1080p30 = 'Hp30', - bmdModeHD1080p50 = 'Hp50', - bmdModeHD1080p5994 = 'Hp59', - bmdModeHD1080p6000 = 'Hp60', // N.B. This _really_ is 60.00 Hz. - bmdModeHD1080i50 = 'Hi50', - bmdModeHD1080i5994 = 'Hi59', - bmdModeHD1080i6000 = 'Hi60', // N.B. This _really_ is 60.00 Hz. + bmdModeHD1080p2398 = /* '23ps' */ 0x32337073, + bmdModeHD1080p24 = /* '24ps' */ 0x32347073, + bmdModeHD1080p25 = /* 'Hp25' */ 0x48703235, + bmdModeHD1080p2997 = /* 'Hp29' */ 0x48703239, + bmdModeHD1080p30 = /* 'Hp30' */ 0x48703330, + bmdModeHD1080p4795 = /* 'Hp47' */ 0x48703437, + bmdModeHD1080p48 = /* 'Hp48' */ 0x48703438, + bmdModeHD1080p50 = /* 'Hp50' */ 0x48703530, + bmdModeHD1080p5994 = /* 'Hp59' */ 0x48703539, + bmdModeHD1080p6000 = /* 'Hp60' */ 0x48703630, // N.B. This _really_ is 60.00 Hz. + bmdModeHD1080p9590 = /* 'Hp95' */ 0x48703935, + bmdModeHD1080p96 = /* 'Hp96' */ 0x48703936, + bmdModeHD1080p100 = /* 'Hp10' */ 0x48703130, + bmdModeHD1080p11988 = /* 'Hp11' */ 0x48703131, + bmdModeHD1080p120 = /* 'Hp12' */ 0x48703132, + bmdModeHD1080i50 = /* 'Hi50' */ 0x48693530, + bmdModeHD1080i5994 = /* 'Hi59' */ 0x48693539, + bmdModeHD1080i6000 = /* 'Hi60' */ 0x48693630, // N.B. This _really_ is 60.00 Hz. /* HD 720 Modes */ - bmdModeHD720p50 = 'hp50', - bmdModeHD720p5994 = 'hp59', - bmdModeHD720p60 = 'hp60', + bmdModeHD720p50 = /* 'hp50' */ 0x68703530, + bmdModeHD720p5994 = /* 'hp59' */ 0x68703539, + bmdModeHD720p60 = /* 'hp60' */ 0x68703630, /* 2K Modes */ - bmdMode2k2398 = '2k23', - bmdMode2k24 = '2k24', - bmdMode2k25 = '2k25', + bmdMode2k2398 = /* '2k23' */ 0x326B3233, + bmdMode2k24 = /* '2k24' */ 0x326B3234, + bmdMode2k25 = /* '2k25' */ 0x326B3235, /* 2K DCI Modes */ - bmdMode2kDCI2398 = '2d23', - bmdMode2kDCI24 = '2d24', - bmdMode2kDCI25 = '2d25', - bmdMode2kDCI2997 = '2d29', - bmdMode2kDCI30 = '2d30', - bmdMode2kDCI50 = '2d50', - bmdMode2kDCI5994 = '2d59', - bmdMode2kDCI60 = '2d60', + bmdMode2kDCI2398 = /* '2d23' */ 0x32643233, + bmdMode2kDCI24 = /* '2d24' */ 0x32643234, + bmdMode2kDCI25 = /* '2d25' */ 0x32643235, + bmdMode2kDCI2997 = /* '2d29' */ 0x32643239, + bmdMode2kDCI30 = /* '2d30' */ 0x32643330, + bmdMode2kDCI4795 = /* '2d47' */ 0x32643437, + bmdMode2kDCI48 = /* '2d48' */ 0x32643438, + bmdMode2kDCI50 = /* '2d50' */ 0x32643530, + bmdMode2kDCI5994 = /* '2d59' */ 0x32643539, + bmdMode2kDCI60 = /* '2d60' */ 0x32643630, + bmdMode2kDCI9590 = /* '2d95' */ 0x32643935, + bmdMode2kDCI96 = /* '2d96' */ 0x32643936, + bmdMode2kDCI100 = /* '2d10' */ 0x32643130, + bmdMode2kDCI11988 = /* '2d11' */ 0x32643131, + bmdMode2kDCI120 = /* '2d12' */ 0x32643132, /* 4K UHD Modes */ - bmdMode4K2160p2398 = '4k23', - bmdMode4K2160p24 = '4k24', - bmdMode4K2160p25 = '4k25', - bmdMode4K2160p2997 = '4k29', - bmdMode4K2160p30 = '4k30', - bmdMode4K2160p50 = '4k50', - bmdMode4K2160p5994 = '4k59', - bmdMode4K2160p60 = '4k60', + bmdMode4K2160p2398 = /* '4k23' */ 0x346B3233, + bmdMode4K2160p24 = /* '4k24' */ 0x346B3234, + bmdMode4K2160p25 = /* '4k25' */ 0x346B3235, + bmdMode4K2160p2997 = /* '4k29' */ 0x346B3239, + bmdMode4K2160p30 = /* '4k30' */ 0x346B3330, + bmdMode4K2160p4795 = /* '4k47' */ 0x346B3437, + bmdMode4K2160p48 = /* '4k48' */ 0x346B3438, + bmdMode4K2160p50 = /* '4k50' */ 0x346B3530, + bmdMode4K2160p5994 = /* '4k59' */ 0x346B3539, + bmdMode4K2160p60 = /* '4k60' */ 0x346B3630, + bmdMode4K2160p9590 = /* '4k95' */ 0x346B3935, + bmdMode4K2160p96 = /* '4k96' */ 0x346B3936, + bmdMode4K2160p100 = /* '4k10' */ 0x346B3130, + bmdMode4K2160p11988 = /* '4k11' */ 0x346B3131, + bmdMode4K2160p120 = /* '4k12' */ 0x346B3132, /* 4K DCI Modes */ - bmdMode4kDCI2398 = '4d23', - bmdMode4kDCI24 = '4d24', - bmdMode4kDCI25 = '4d25', - bmdMode4kDCI2997 = '4d29', - bmdMode4kDCI30 = '4d30', - bmdMode4kDCI50 = '4d50', - bmdMode4kDCI5994 = '4d59', - bmdMode4kDCI60 = '4d60', + bmdMode4kDCI2398 = /* '4d23' */ 0x34643233, + bmdMode4kDCI24 = /* '4d24' */ 0x34643234, + bmdMode4kDCI25 = /* '4d25' */ 0x34643235, + bmdMode4kDCI2997 = /* '4d29' */ 0x34643239, + bmdMode4kDCI30 = /* '4d30' */ 0x34643330, + bmdMode4kDCI4795 = /* '4d47' */ 0x34643437, + bmdMode4kDCI48 = /* '4d48' */ 0x34643438, + bmdMode4kDCI50 = /* '4d50' */ 0x34643530, + bmdMode4kDCI5994 = /* '4d59' */ 0x34643539, + bmdMode4kDCI60 = /* '4d60' */ 0x34643630, + bmdMode4kDCI9590 = /* '4d95' */ 0x34643935, + bmdMode4kDCI96 = /* '4d96' */ 0x34643936, + bmdMode4kDCI100 = /* '4d10' */ 0x34643130, + bmdMode4kDCI11988 = /* '4d11' */ 0x34643131, + bmdMode4kDCI120 = /* '4d12' */ 0x34643132, /* 8K UHD Modes */ - bmdMode8K4320p2398 = '8k23', - bmdMode8K4320p24 = '8k24', - bmdMode8K4320p25 = '8k25', - bmdMode8K4320p2997 = '8k29', - bmdMode8K4320p30 = '8k30', - bmdMode8K4320p50 = '8k50', - bmdMode8K4320p5994 = '8k59', - bmdMode8K4320p60 = '8k60', + bmdMode8K4320p2398 = /* '8k23' */ 0x386B3233, + bmdMode8K4320p24 = /* '8k24' */ 0x386B3234, + bmdMode8K4320p25 = /* '8k25' */ 0x386B3235, + bmdMode8K4320p2997 = /* '8k29' */ 0x386B3239, + bmdMode8K4320p30 = /* '8k30' */ 0x386B3330, + bmdMode8K4320p4795 = /* '8k47' */ 0x386B3437, + bmdMode8K4320p48 = /* '8k48' */ 0x386B3438, + bmdMode8K4320p50 = /* '8k50' */ 0x386B3530, + bmdMode8K4320p5994 = /* '8k59' */ 0x386B3539, + bmdMode8K4320p60 = /* '8k60' */ 0x386B3630, /* 8K DCI Modes */ - bmdMode8kDCI2398 = '8d23', - bmdMode8kDCI24 = '8d24', - bmdMode8kDCI25 = '8d25', - bmdMode8kDCI2997 = '8d29', - bmdMode8kDCI30 = '8d30', - bmdMode8kDCI50 = '8d50', - bmdMode8kDCI5994 = '8d59', - bmdMode8kDCI60 = '8d60', + bmdMode8kDCI2398 = /* '8d23' */ 0x38643233, + bmdMode8kDCI24 = /* '8d24' */ 0x38643234, + bmdMode8kDCI25 = /* '8d25' */ 0x38643235, + bmdMode8kDCI2997 = /* '8d29' */ 0x38643239, + bmdMode8kDCI30 = /* '8d30' */ 0x38643330, + bmdMode8kDCI4795 = /* '8d47' */ 0x38643437, + bmdMode8kDCI48 = /* '8d48' */ 0x38643438, + bmdMode8kDCI50 = /* '8d50' */ 0x38643530, + bmdMode8kDCI5994 = /* '8d59' */ 0x38643539, + bmdMode8kDCI60 = /* '8d60' */ 0x38643630, - /* RAW Modes for Cintel (input only) */ + /* PC Modes */ - bmdModeCintelRAW = 'rwci', // Frame size up to 4096x3072, variable frame rate - bmdModeCintelCompressedRAW = 'rwcc', // Frame size up to 4096x3072, variable frame rate + bmdMode640x480p60 = /* 'vga6' */ 0x76676136, + bmdMode800x600p60 = /* 'svg6' */ 0x73766736, + bmdMode1440x900p50 = /* 'wxg5' */ 0x77786735, + bmdMode1440x900p60 = /* 'wxg6' */ 0x77786736, + bmdMode1440x1080p50 = /* 'sxg5' */ 0x73786735, + bmdMode1440x1080p60 = /* 'sxg6' */ 0x73786736, + bmdMode1600x1200p50 = /* 'uxg5' */ 0x75786735, + bmdMode1600x1200p60 = /* 'uxg6' */ 0x75786736, + bmdMode1920x1200p50 = /* 'wux5' */ 0x77757835, + bmdMode1920x1200p60 = /* 'wux6' */ 0x77757836, + bmdMode1920x1440p50 = /* '1945' */ 0x31393435, + bmdMode1920x1440p60 = /* '1946' */ 0x31393436, + bmdMode2560x1440p50 = /* 'wqh5' */ 0x77716835, + bmdMode2560x1440p60 = /* 'wqh6' */ 0x77716836, + bmdMode2560x1600p50 = /* 'wqx5' */ 0x77717835, + bmdMode2560x1600p60 = /* 'wqx6' */ 0x77717836, /* Special Modes */ - bmdModeUnknown = 'iunk' + bmdModeUnknown = /* 'iunk' */ 0x69756E6B }; -/* Enum BMDFieldDominance - Video field dominance */ +/* Enum BMDFieldDominance - BMDFieldDominance enumerates settings applicable to video fields. */ typedef uint32_t BMDFieldDominance; enum _BMDFieldDominance { bmdUnknownFieldDominance = 0, - bmdLowerFieldFirst = 'lowr', - bmdUpperFieldFirst = 'uppr', - bmdProgressiveFrame = 'prog', - bmdProgressiveSegmentedFrame = 'psf ' + bmdLowerFieldFirst = /* 'lowr' */ 0x6C6F7772, + bmdUpperFieldFirst = /* 'uppr' */ 0x75707072, + bmdProgressiveFrame = /* 'prog' */ 0x70726F67, + bmdProgressiveSegmentedFrame = /* 'psf ' */ 0x70736620 }; /* Enum BMDPixelFormat - Video pixel formats supported for output/input */ typedef uint32_t BMDPixelFormat; enum _BMDPixelFormat { - bmdFormat8BitYUV = '2vuy', - bmdFormat10BitYUV = 'v210', + bmdFormatUnspecified = 0, + bmdFormat8BitYUV = /* '2vuy' */ 0x32767579, + bmdFormat10BitYUV = /* 'v210' */ 0x76323130, bmdFormat8BitARGB = 32, - bmdFormat8BitBGRA = 'BGRA', - bmdFormat10BitRGB = 'r210', // Big-endian RGB 10-bit per component with SMPTE video levels (64-960). Packed as 2:10:10:10 - bmdFormat12BitRGB = 'R12B', // Big-endian RGB 12-bit per component with full range (0-4095). Packed as 12-bit per component - bmdFormat12BitRGBLE = 'R12L', // Little-endian RGB 12-bit per component with full range (0-4095). Packed as 12-bit per component - bmdFormat10BitRGBXLE = 'R10l', // Little-endian 10-bit RGB with SMPTE video levels (64-940) - bmdFormat10BitRGBX = 'R10b', // Big-endian 10-bit RGB with SMPTE video levels (64-940) - bmdFormatH265 = 'hev1', // High Efficiency Video Coding (HEVC/h.265) + bmdFormat8BitBGRA = /* 'BGRA' */ 0x42475241, + bmdFormat10BitRGB = /* 'r210' */ 0x72323130, // Big-endian RGB 10-bit per component with SMPTE video levels (64-960). Packed as 2:10:10:10 + bmdFormat12BitRGB = /* 'R12B' */ 0x52313242, // Big-endian RGB 12-bit per component with full range (0-4095). Packed as 12-bit per component + bmdFormat12BitRGBLE = /* 'R12L' */ 0x5231324C, // Little-endian RGB 12-bit per component with full range (0-4095). Packed as 12-bit per component + bmdFormat10BitRGBXLE = /* 'R10l' */ 0x5231306C, // Little-endian 10-bit RGB with SMPTE video levels (64-940) + bmdFormat10BitRGBX = /* 'R10b' */ 0x52313062, // Big-endian 10-bit RGB with SMPTE video levels (64-940) + bmdFormatH265 = /* 'hev1' */ 0x68657631, // High Efficiency Video Coding (HEVC/h.265) /* AVID DNxHR */ - bmdFormatDNxHR = 'AVdh', - - /* Cintel formats */ - - bmdFormat12BitRAWGRBG = 'r12p', // 12-bit RAW data for bayer pattern GRBG - bmdFormat12BitRAWJPEG = 'r16p' // 12-bit RAW data arranged in tiles and JPEG compressed + bmdFormatDNxHR = /* 'AVdh' */ 0x41566468 }; /* Enum BMDDisplayModeFlags - Flags to describe the characteristics of an IDeckLinkDisplayMode. */ @@ -199,32 +241,34 @@ enum _BMDDisplayModeFlags { bmdDisplayModeColorspaceRec2020 = 1 << 3 }; +#if defined(__cplusplus) + // Forward Declarations class IDeckLinkDisplayModeIterator; class IDeckLinkDisplayMode; -/* Interface IDeckLinkDisplayModeIterator - enumerates over supported input/output display modes. */ +/* Interface IDeckLinkDisplayModeIterator - Enumerates over supported input/output display modes. */ class BMD_PUBLIC IDeckLinkDisplayModeIterator : public IUnknown { public: - virtual HRESULT Next (/* out */ IDeckLinkDisplayMode **deckLinkDisplayMode) = 0; + virtual HRESULT Next (/* out */ IDeckLinkDisplayMode** deckLinkDisplayMode) = 0; protected: virtual ~IDeckLinkDisplayModeIterator () {} // call Release method to drop reference count }; -/* Interface IDeckLinkDisplayMode - represents a display mode */ +/* Interface IDeckLinkDisplayMode - Represents a display mode */ class BMD_PUBLIC IDeckLinkDisplayMode : public IUnknown { public: - virtual HRESULT GetName (/* out */ CFStringRef *name) = 0; + virtual HRESULT GetName (/* out */ CFStringRef* name) = 0; virtual BMDDisplayMode GetDisplayMode (void) = 0; virtual long GetWidth (void) = 0; virtual long GetHeight (void) = 0; - virtual HRESULT GetFrameRate (/* out */ BMDTimeValue *frameDuration, /* out */ BMDTimeScale *timeScale) = 0; + virtual HRESULT GetFrameRate (/* out */ BMDTimeValue* frameDuration, /* out */ BMDTimeScale* timeScale) = 0; virtual BMDFieldDominance GetFieldDominance (void) = 0; virtual BMDDisplayModeFlags GetFlags (void) = 0; @@ -239,5 +283,5 @@ extern "C" { } - +#endif /* defined(__cplusplus) */ #endif /* defined(BMD_DECKLINKAPIMODES_H) */ diff --git a/plugins/decklink/mac/decklink-sdk/DeckLinkAPIStreaming.h b/plugins/decklink/mac/decklink-sdk/DeckLinkAPIStreaming.h index c2d357c..15faf08 100644 --- a/plugins/decklink/mac/decklink-sdk/DeckLinkAPIStreaming.h +++ b/plugins/decklink/mac/decklink-sdk/DeckLinkAPIStreaming.h @@ -1,5 +1,5 @@ /* -LICENSE-START- -** Copyright (c) 2018 Blackmagic Design +** Copyright (c) 2020 Blackmagic Design ** ** Permission is hereby granted, free of charge, to any person or organization ** obtaining a copy of the software and accompanying documentation covered by @@ -7,14 +7,14 @@ ** execute, and transmit the Software, and to prepare derivative works of the ** Software, and to permit third-parties to whom the Software is furnished to ** do so, all subject to the following: -** +** ** The copyright notices in the Software and this entire statement, including ** the above license grant, this restriction and the following disclaimer, ** must be included in all copies of the Software, in whole or in part, and ** all derivative works of the Software, unless such copies or derivative ** works are solely in the form of machine-executable object code generated by ** a source language processor. -** +** ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT @@ -46,26 +46,26 @@ // Interface ID Declarations -BMD_CONST REFIID IID_IBMDStreamingDeviceNotificationCallback = /* F9531D64-3305-4B29-A387-7F74BB0D0E84 */ {0xF9,0x53,0x1D,0x64,0x33,0x05,0x4B,0x29,0xA3,0x87,0x7F,0x74,0xBB,0x0D,0x0E,0x84}; -BMD_CONST REFIID IID_IBMDStreamingH264InputCallback = /* 823C475F-55AE-46F9-890C-537CC5CEDCCA */ {0x82,0x3C,0x47,0x5F,0x55,0xAE,0x46,0xF9,0x89,0x0C,0x53,0x7C,0xC5,0xCE,0xDC,0xCA}; -BMD_CONST REFIID IID_IBMDStreamingDiscovery = /* 2C837444-F989-4D87-901A-47C8A36D096D */ {0x2C,0x83,0x74,0x44,0xF9,0x89,0x4D,0x87,0x90,0x1A,0x47,0xC8,0xA3,0x6D,0x09,0x6D}; -BMD_CONST REFIID IID_IBMDStreamingVideoEncodingMode = /* 1AB8035B-CD13-458D-B6DF-5E8F7C2141D9 */ {0x1A,0xB8,0x03,0x5B,0xCD,0x13,0x45,0x8D,0xB6,0xDF,0x5E,0x8F,0x7C,0x21,0x41,0xD9}; -BMD_CONST REFIID IID_IBMDStreamingMutableVideoEncodingMode = /* 19BF7D90-1E0A-400D-B2C6-FFC4E78AD49D */ {0x19,0xBF,0x7D,0x90,0x1E,0x0A,0x40,0x0D,0xB2,0xC6,0xFF,0xC4,0xE7,0x8A,0xD4,0x9D}; -BMD_CONST REFIID IID_IBMDStreamingVideoEncodingModePresetIterator = /* 7AC731A3-C950-4AD0-804A-8377AA51C6C4 */ {0x7A,0xC7,0x31,0xA3,0xC9,0x50,0x4A,0xD0,0x80,0x4A,0x83,0x77,0xAA,0x51,0xC6,0xC4}; -BMD_CONST REFIID IID_IBMDStreamingDeviceInput = /* 24B6B6EC-1727-44BB-9818-34FF086ACF98 */ {0x24,0xB6,0xB6,0xEC,0x17,0x27,0x44,0xBB,0x98,0x18,0x34,0xFF,0x08,0x6A,0xCF,0x98}; -BMD_CONST REFIID IID_IBMDStreamingH264NALPacket = /* E260E955-14BE-4395-9775-9F02CC0A9D89 */ {0xE2,0x60,0xE9,0x55,0x14,0xBE,0x43,0x95,0x97,0x75,0x9F,0x02,0xCC,0x0A,0x9D,0x89}; -BMD_CONST REFIID IID_IBMDStreamingAudioPacket = /* D9EB5902-1AD2-43F4-9E2C-3CFA50B5EE19 */ {0xD9,0xEB,0x59,0x02,0x1A,0xD2,0x43,0xF4,0x9E,0x2C,0x3C,0xFA,0x50,0xB5,0xEE,0x19}; -BMD_CONST REFIID IID_IBMDStreamingMPEG2TSPacket = /* 91810D1C-4FB3-4AAA-AE56-FA301D3DFA4C */ {0x91,0x81,0x0D,0x1C,0x4F,0xB3,0x4A,0xAA,0xAE,0x56,0xFA,0x30,0x1D,0x3D,0xFA,0x4C}; -BMD_CONST REFIID IID_IBMDStreamingH264NALParser = /* 5867F18C-5BFA-4CCC-B2A7-9DFD140417D2 */ {0x58,0x67,0xF1,0x8C,0x5B,0xFA,0x4C,0xCC,0xB2,0xA7,0x9D,0xFD,0x14,0x04,0x17,0xD2}; +BMD_CONST REFIID IID_IBMDStreamingDeviceNotificationCallback = /* F9531D64-3305-4B29-A387-7F74BB0D0E84 */ { 0xF9,0x53,0x1D,0x64,0x33,0x05,0x4B,0x29,0xA3,0x87,0x7F,0x74,0xBB,0x0D,0x0E,0x84 }; +BMD_CONST REFIID IID_IBMDStreamingH264InputCallback = /* 823C475F-55AE-46F9-890C-537CC5CEDCCA */ { 0x82,0x3C,0x47,0x5F,0x55,0xAE,0x46,0xF9,0x89,0x0C,0x53,0x7C,0xC5,0xCE,0xDC,0xCA }; +BMD_CONST REFIID IID_IBMDStreamingDiscovery = /* 2C837444-F989-4D87-901A-47C8A36D096D */ { 0x2C,0x83,0x74,0x44,0xF9,0x89,0x4D,0x87,0x90,0x1A,0x47,0xC8,0xA3,0x6D,0x09,0x6D }; +BMD_CONST REFIID IID_IBMDStreamingVideoEncodingMode = /* 1AB8035B-CD13-458D-B6DF-5E8F7C2141D9 */ { 0x1A,0xB8,0x03,0x5B,0xCD,0x13,0x45,0x8D,0xB6,0xDF,0x5E,0x8F,0x7C,0x21,0x41,0xD9 }; +BMD_CONST REFIID IID_IBMDStreamingMutableVideoEncodingMode = /* 19BF7D90-1E0A-400D-B2C6-FFC4E78AD49D */ { 0x19,0xBF,0x7D,0x90,0x1E,0x0A,0x40,0x0D,0xB2,0xC6,0xFF,0xC4,0xE7,0x8A,0xD4,0x9D }; +BMD_CONST REFIID IID_IBMDStreamingVideoEncodingModePresetIterator = /* 7AC731A3-C950-4AD0-804A-8377AA51C6C4 */ { 0x7A,0xC7,0x31,0xA3,0xC9,0x50,0x4A,0xD0,0x80,0x4A,0x83,0x77,0xAA,0x51,0xC6,0xC4 }; +BMD_CONST REFIID IID_IBMDStreamingDeviceInput = /* 24B6B6EC-1727-44BB-9818-34FF086ACF98 */ { 0x24,0xB6,0xB6,0xEC,0x17,0x27,0x44,0xBB,0x98,0x18,0x34,0xFF,0x08,0x6A,0xCF,0x98 }; +BMD_CONST REFIID IID_IBMDStreamingH264NALPacket = /* E260E955-14BE-4395-9775-9F02CC0A9D89 */ { 0xE2,0x60,0xE9,0x55,0x14,0xBE,0x43,0x95,0x97,0x75,0x9F,0x02,0xCC,0x0A,0x9D,0x89 }; +BMD_CONST REFIID IID_IBMDStreamingAudioPacket = /* D9EB5902-1AD2-43F4-9E2C-3CFA50B5EE19 */ { 0xD9,0xEB,0x59,0x02,0x1A,0xD2,0x43,0xF4,0x9E,0x2C,0x3C,0xFA,0x50,0xB5,0xEE,0x19 }; +BMD_CONST REFIID IID_IBMDStreamingMPEG2TSPacket = /* 91810D1C-4FB3-4AAA-AE56-FA301D3DFA4C */ { 0x91,0x81,0x0D,0x1C,0x4F,0xB3,0x4A,0xAA,0xAE,0x56,0xFA,0x30,0x1D,0x3D,0xFA,0x4C }; +BMD_CONST REFIID IID_IBMDStreamingH264NALParser = /* 5867F18C-5BFA-4CCC-B2A7-9DFD140417D2 */ { 0x58,0x67,0xF1,0x8C,0x5B,0xFA,0x4C,0xCC,0xB2,0xA7,0x9D,0xFD,0x14,0x04,0x17,0xD2 }; /* Enum BMDStreamingDeviceMode - Device modes */ typedef uint32_t BMDStreamingDeviceMode; enum _BMDStreamingDeviceMode { - bmdStreamingDeviceIdle = 'idle', - bmdStreamingDeviceEncoding = 'enco', - bmdStreamingDeviceStopping = 'stop', - bmdStreamingDeviceUnknown = 'munk' + bmdStreamingDeviceIdle = /* 'idle' */ 0x69646C65, + bmdStreamingDeviceEncoding = /* 'enco' */ 0x656E636F, + bmdStreamingDeviceStopping = /* 'stop' */ 0x73746F70, + bmdStreamingDeviceUnknown = /* 'munk' */ 0x6D756E6B }; /* Enum BMDStreamingEncodingFrameRate - Encoded frame rates */ @@ -75,20 +75,20 @@ enum _BMDStreamingEncodingFrameRate { /* Interlaced rates */ - bmdStreamingEncodedFrameRate50i = 'e50i', - bmdStreamingEncodedFrameRate5994i = 'e59i', - bmdStreamingEncodedFrameRate60i = 'e60i', + bmdStreamingEncodedFrameRate50i = /* 'e50i' */ 0x65353069, + bmdStreamingEncodedFrameRate5994i = /* 'e59i' */ 0x65353969, + bmdStreamingEncodedFrameRate60i = /* 'e60i' */ 0x65363069, /* Progressive rates */ - bmdStreamingEncodedFrameRate2398p = 'e23p', - bmdStreamingEncodedFrameRate24p = 'e24p', - bmdStreamingEncodedFrameRate25p = 'e25p', - bmdStreamingEncodedFrameRate2997p = 'e29p', - bmdStreamingEncodedFrameRate30p = 'e30p', - bmdStreamingEncodedFrameRate50p = 'e50p', - bmdStreamingEncodedFrameRate5994p = 'e59p', - bmdStreamingEncodedFrameRate60p = 'e60p' + bmdStreamingEncodedFrameRate2398p = /* 'e23p' */ 0x65323370, + bmdStreamingEncodedFrameRate24p = /* 'e24p' */ 0x65323470, + bmdStreamingEncodedFrameRate25p = /* 'e25p' */ 0x65323570, + bmdStreamingEncodedFrameRate2997p = /* 'e29p' */ 0x65323970, + bmdStreamingEncodedFrameRate30p = /* 'e30p' */ 0x65333070, + bmdStreamingEncodedFrameRate50p = /* 'e50p' */ 0x65353070, + bmdStreamingEncodedFrameRate5994p = /* 'e59p' */ 0x65353970, + bmdStreamingEncodedFrameRate60p = /* 'e60p' */ 0x65363070 }; /* Enum BMDStreamingEncodingSupport - Output encoding mode supported flag */ @@ -96,56 +96,56 @@ enum _BMDStreamingEncodingFrameRate { typedef uint32_t BMDStreamingEncodingSupport; enum _BMDStreamingEncodingSupport { bmdStreamingEncodingModeNotSupported = 0, - bmdStreamingEncodingModeSupported, - bmdStreamingEncodingModeSupportedWithChanges + bmdStreamingEncodingModeSupported, + bmdStreamingEncodingModeSupportedWithChanges }; /* Enum BMDStreamingVideoCodec - Video codecs */ typedef uint32_t BMDStreamingVideoCodec; enum _BMDStreamingVideoCodec { - bmdStreamingVideoCodecH264 = 'H264' + bmdStreamingVideoCodecH264 = /* 'H264' */ 0x48323634 }; /* Enum BMDStreamingH264Profile - H264 encoding profile */ typedef uint32_t BMDStreamingH264Profile; enum _BMDStreamingH264Profile { - bmdStreamingH264ProfileHigh = 'high', - bmdStreamingH264ProfileMain = 'main', - bmdStreamingH264ProfileBaseline = 'base' + bmdStreamingH264ProfileHigh = /* 'high' */ 0x68696768, + bmdStreamingH264ProfileMain = /* 'main' */ 0x6D61696E, + bmdStreamingH264ProfileBaseline = /* 'base' */ 0x62617365 }; /* Enum BMDStreamingH264Level - H264 encoding level */ typedef uint32_t BMDStreamingH264Level; enum _BMDStreamingH264Level { - bmdStreamingH264Level12 = 'lv12', - bmdStreamingH264Level13 = 'lv13', - bmdStreamingH264Level2 = 'lv2 ', - bmdStreamingH264Level21 = 'lv21', - bmdStreamingH264Level22 = 'lv22', - bmdStreamingH264Level3 = 'lv3 ', - bmdStreamingH264Level31 = 'lv31', - bmdStreamingH264Level32 = 'lv32', - bmdStreamingH264Level4 = 'lv4 ', - bmdStreamingH264Level41 = 'lv41', - bmdStreamingH264Level42 = 'lv42' + bmdStreamingH264Level12 = /* 'lv12' */ 0x6C763132, + bmdStreamingH264Level13 = /* 'lv13' */ 0x6C763133, + bmdStreamingH264Level2 = /* 'lv2 ' */ 0x6C763220, + bmdStreamingH264Level21 = /* 'lv21' */ 0x6C763231, + bmdStreamingH264Level22 = /* 'lv22' */ 0x6C763232, + bmdStreamingH264Level3 = /* 'lv3 ' */ 0x6C763320, + bmdStreamingH264Level31 = /* 'lv31' */ 0x6C763331, + bmdStreamingH264Level32 = /* 'lv32' */ 0x6C763332, + bmdStreamingH264Level4 = /* 'lv4 ' */ 0x6C763420, + bmdStreamingH264Level41 = /* 'lv41' */ 0x6C763431, + bmdStreamingH264Level42 = /* 'lv42' */ 0x6C763432 }; /* Enum BMDStreamingH264EntropyCoding - H264 entropy coding */ typedef uint32_t BMDStreamingH264EntropyCoding; enum _BMDStreamingH264EntropyCoding { - bmdStreamingH264EntropyCodingCAVLC = 'EVLC', - bmdStreamingH264EntropyCodingCABAC = 'EBAC' + bmdStreamingH264EntropyCodingCAVLC = /* 'EVLC' */ 0x45564C43, + bmdStreamingH264EntropyCodingCABAC = /* 'EBAC' */ 0x45424143 }; /* Enum BMDStreamingAudioCodec - Audio codecs */ typedef uint32_t BMDStreamingAudioCodec; enum _BMDStreamingAudioCodec { - bmdStreamingAudioCodecAAC = 'AAC ' + bmdStreamingAudioCodecAAC = /* 'AAC ' */ 0x41414320 }; /* Enum BMDStreamingEncodingModePropertyID - Encoding mode properties */ @@ -155,27 +155,29 @@ enum _BMDStreamingEncodingModePropertyID { /* Integers, Video Properties */ - bmdStreamingEncodingPropertyVideoFrameRate = 'vfrt', // Uses values of type BMDStreamingEncodingFrameRate - bmdStreamingEncodingPropertyVideoBitRateKbps = 'vbrt', + bmdStreamingEncodingPropertyVideoFrameRate = /* 'vfrt' */ 0x76667274, // Uses values of type BMDStreamingEncodingFrameRate + bmdStreamingEncodingPropertyVideoBitRateKbps = /* 'vbrt' */ 0x76627274, /* Integers, H264 Properties */ - bmdStreamingEncodingPropertyH264Profile = 'hprf', - bmdStreamingEncodingPropertyH264Level = 'hlvl', - bmdStreamingEncodingPropertyH264EntropyCoding = 'hent', + bmdStreamingEncodingPropertyH264Profile = /* 'hprf' */ 0x68707266, + bmdStreamingEncodingPropertyH264Level = /* 'hlvl' */ 0x686C766C, + bmdStreamingEncodingPropertyH264EntropyCoding = /* 'hent' */ 0x68656E74, /* Flags, H264 Properties */ - bmdStreamingEncodingPropertyH264HasBFrames = 'hBfr', + bmdStreamingEncodingPropertyH264HasBFrames = /* 'hBfr' */ 0x68426672, /* Integers, Audio Properties */ - bmdStreamingEncodingPropertyAudioCodec = 'acdc', - bmdStreamingEncodingPropertyAudioSampleRate = 'asrt', - bmdStreamingEncodingPropertyAudioChannelCount = 'achc', - bmdStreamingEncodingPropertyAudioBitRateKbps = 'abrt' + bmdStreamingEncodingPropertyAudioCodec = /* 'acdc' */ 0x61636463, + bmdStreamingEncodingPropertyAudioSampleRate = /* 'asrt' */ 0x61737274, + bmdStreamingEncodingPropertyAudioChannelCount = /* 'achc' */ 0x61636863, + bmdStreamingEncodingPropertyAudioBitRateKbps = /* 'abrt' */ 0x61627274 }; +#if defined(__cplusplus) + // Forward Declarations class IBMDStreamingDeviceNotificationCallback; @@ -236,7 +238,7 @@ protected: class BMD_PUBLIC IBMDStreamingVideoEncodingMode : public IUnknown { public: - virtual HRESULT GetName (/* out */ CFStringRef *name) = 0; + virtual HRESULT GetName (/* out */ CFStringRef* name) = 0; virtual unsigned int GetPresetID (void) = 0; virtual unsigned int GetSourcePositionX (void) = 0; virtual unsigned int GetSourcePositionY (void) = 0; @@ -247,8 +249,8 @@ public: virtual HRESULT GetFlag (/* in */ BMDStreamingEncodingModePropertyID cfgID, /* out */ bool* value) = 0; virtual HRESULT GetInt (/* in */ BMDStreamingEncodingModePropertyID cfgID, /* out */ int64_t* value) = 0; virtual HRESULT GetFloat (/* in */ BMDStreamingEncodingModePropertyID cfgID, /* out */ double* value) = 0; - virtual HRESULT GetString (/* in */ BMDStreamingEncodingModePropertyID cfgID, /* out */ CFStringRef *value) = 0; - virtual HRESULT CreateMutableVideoEncodingMode (/* out */ IBMDStreamingMutableVideoEncodingMode** newEncodingMode) = 0; // Creates a mutable copy of the encoding mode + virtual HRESULT GetString (/* in */ BMDStreamingEncodingModePropertyID cfgID, /* out */ CFStringRef* value) = 0; + virtual HRESULT CreateMutableVideoEncodingMode (/* out */ IBMDStreamingMutableVideoEncodingMode** newEncodingMode) = 0; // Creates a mutable copy of the encoding mode protected: virtual ~IBMDStreamingVideoEncodingMode () {} // call Release method to drop reference count @@ -318,9 +320,9 @@ class BMD_PUBLIC IBMDStreamingH264NALPacket : public IUnknown public: virtual long GetPayloadSize (void) = 0; virtual HRESULT GetBytes (/* out */ void** buffer) = 0; - virtual HRESULT GetBytesWithSizePrefix (/* out */ void** buffer) = 0; // Contains a 32-bit unsigned big endian size prefix + virtual HRESULT GetBytesWithSizePrefix (/* out */ void** buffer) = 0; // Contains a 32-bit unsigned big endian size prefix virtual HRESULT GetDisplayTime (/* in */ uint64_t requestedTimeScale, /* out */ uint64_t* displayTime) = 0; - virtual HRESULT GetPacketIndex (/* out */ uint32_t* packetIndex) = 0; // Deprecated + virtual HRESULT GetPacketIndex (/* out */ uint32_t* packetIndex) = 0; // Deprecated protected: virtual ~IBMDStreamingH264NALPacket () {} // call Release method to drop reference count @@ -335,7 +337,7 @@ public: virtual long GetPayloadSize (void) = 0; virtual HRESULT GetBytes (/* out */ void** buffer) = 0; virtual HRESULT GetPlayTime (/* in */ uint64_t requestedTimeScale, /* out */ uint64_t* playTime) = 0; - virtual HRESULT GetPacketIndex (/* out */ uint32_t* packetIndex) = 0; // Deprecated + virtual HRESULT GetPacketIndex (/* out */ uint32_t* packetIndex) = 0; // Deprecated protected: virtual ~IBMDStreamingAudioPacket () {} // call Release method to drop reference count @@ -370,10 +372,10 @@ protected: extern "C" { - IBMDStreamingDiscovery* BMD_PUBLIC CreateBMDStreamingDiscoveryInstance (void); - IBMDStreamingH264NALParser* BMD_PUBLIC CreateBMDStreamingH264NALParser (void); + IBMDStreamingDiscovery* BMD_PUBLIC CreateBMDStreamingDiscoveryInstance(void); + IBMDStreamingH264NALParser* BMD_PUBLIC CreateBMDStreamingH264NALParser(void); } - +#endif /* defined(__cplusplus) */ #endif /* defined(BMD_DECKLINKAPISTREAMING_H) */ diff --git a/plugins/decklink/mac/decklink-sdk/DeckLinkAPIStreaming_v10_11.h b/plugins/decklink/mac/decklink-sdk/DeckLinkAPIStreaming_v10_11.h new file mode 100644 index 0000000..3ef8dd7 --- /dev/null +++ b/plugins/decklink/mac/decklink-sdk/DeckLinkAPIStreaming_v10_11.h @@ -0,0 +1,46 @@ +/* -LICENSE-START- +** Copyright (c) 2018 Blackmagic Design +** +** Permission is hereby granted, free of charge, to any person or organization +** obtaining a copy of the software and accompanying documentation covered by +** this license (the "Software") to use, reproduce, display, distribute, +** execute, and transmit the Software, and to prepare derivative works of the +** Software, and to permit third-parties to whom the Software is furnished to +** do so, all subject to the following: +** +** The copyright notices in the Software and this entire statement, including +** the above license grant, this restriction and the following disclaimer, +** must be included in all copies of the Software, in whole or in part, and +** all derivative works of the Software, unless such copies or derivative +** works are solely in the form of machine-executable object code generated by +** a source language processor. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +** SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +** FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +** DEALINGS IN THE SOFTWARE. +** -LICENSE-END- +*/ + +#ifndef BMD_DECKLINKAPISTREAMING_H +#define BMD_DECKLINKAPISTREAMING_H + +#ifndef BMD_PUBLIC + #define BMD_PUBLIC +#endif + + +/* Functions */ + +extern "C" { + + IBMDStreamingDiscovery* BMD_PUBLIC CreateBMDStreamingDiscoveryInstance_v10_11 (void); + IBMDStreamingH264NALParser* BMD_PUBLIC CreateBMDStreamingH264NALParser_v10_11 (void); + +} + + +#endif /* defined(BMD_DECKLINKAPISTREAMING_H) */ diff --git a/plugins/decklink/mac/decklink-sdk/DeckLinkAPITypes.h b/plugins/decklink/mac/decklink-sdk/DeckLinkAPITypes.h index 1564c6e..552e0c1 100644 --- a/plugins/decklink/mac/decklink-sdk/DeckLinkAPITypes.h +++ b/plugins/decklink/mac/decklink-sdk/DeckLinkAPITypes.h @@ -1,5 +1,5 @@ /* -LICENSE-START- -** Copyright (c) 2018 Blackmagic Design +** Copyright (c) 2020 Blackmagic Design ** ** Permission is hereby granted, free of charge, to any person or organization ** obtaining a copy of the software and accompanying documentation covered by @@ -7,14 +7,14 @@ ** execute, and transmit the Software, and to prepare derivative works of the ** Software, and to permit third-parties to whom the Software is furnished to ** do so, all subject to the following: -** +** ** The copyright notices in the Software and this entire statement, including ** the above license grant, this restriction and the following disclaimer, ** must be included in all copies of the Software, in whole or in part, and ** all derivative works of the Software, unless such copies or derivative ** works are solely in the form of machine-executable object code generated by ** a source language processor. -** +** ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT @@ -50,7 +50,7 @@ typedef uint32_t BMDTimecodeUserBits; // Interface ID Declarations -BMD_CONST REFIID IID_IDeckLinkTimecode = /* BC6CFBD3-8317-4325-AC1C-1216391E9340 */ {0xBC,0x6C,0xFB,0xD3,0x83,0x17,0x43,0x25,0xAC,0x1C,0x12,0x16,0x39,0x1E,0x93,0x40}; +BMD_CONST REFIID IID_IDeckLinkTimecode = /* BC6CFBD3-8317-4325-AC1C-1216391E9340 */ { 0xBC,0x6C,0xFB,0xD3,0x83,0x17,0x43,0x25,0xAC,0x1C,0x12,0x16,0x39,0x1E,0x93,0x40 }; /* Enum BMDTimecodeFlags - Timecode flags */ @@ -59,13 +59,16 @@ enum _BMDTimecodeFlags { bmdTimecodeFlagDefault = 0, bmdTimecodeIsDropFrame = 1 << 0, bmdTimecodeFieldMark = 1 << 1, - bmdTimecodeColorFrame = 1 << 2 + bmdTimecodeColorFrame = 1 << 2, + bmdTimecodeEmbedRecordingTrigger = 1 << 3, // On SDI recording trigger utilises a user-bit. + bmdTimecodeRecordingTriggered = 1 << 4 }; /* Enum BMDVideoConnection - Video connection types */ typedef uint32_t BMDVideoConnection; enum _BMDVideoConnection { + bmdVideoConnectionUnspecified = 0, bmdVideoConnectionSDI = 1 << 0, bmdVideoConnectionHDMI = 1 << 1, bmdVideoConnectionOpticalSDI = 1 << 2, @@ -95,6 +98,8 @@ enum _BMDDeckControlConnection { bmdDeckControlConnectionRS422Remote2 = 1 << 1 }; +#if defined(__cplusplus) + // Forward Declarations class IDeckLinkTimecode; @@ -105,10 +110,10 @@ class BMD_PUBLIC IDeckLinkTimecode : public IUnknown { public: virtual BMDTimecodeBCD GetBCD (void) = 0; - virtual HRESULT GetComponents (/* out */ uint8_t *hours, /* out */ uint8_t *minutes, /* out */ uint8_t *seconds, /* out */ uint8_t *frames) = 0; - virtual HRESULT GetString (/* out */ CFStringRef *timecode) = 0; + virtual HRESULT GetComponents (/* out */ uint8_t* hours, /* out */ uint8_t* minutes, /* out */ uint8_t* seconds, /* out */ uint8_t* frames) = 0; + virtual HRESULT GetString (/* out */ CFStringRef* timecode) = 0; virtual BMDTimecodeFlags GetFlags (void) = 0; - virtual HRESULT GetTimecodeUserBits (/* out */ BMDTimecodeUserBits *userBits) = 0; + virtual HRESULT GetTimecodeUserBits (/* out */ BMDTimecodeUserBits* userBits) = 0; protected: virtual ~IDeckLinkTimecode () {} // call Release method to drop reference count @@ -121,5 +126,5 @@ extern "C" { } - +#endif /* defined(__cplusplus) */ #endif /* defined(BMD_DECKLINKAPITYPES_H) */ diff --git a/plugins/decklink/mac/decklink-sdk/DeckLinkAPIVersion.h b/plugins/decklink/mac/decklink-sdk/DeckLinkAPIVersion.h index f9db7ff..dcdeeb1 100644 --- a/plugins/decklink/mac/decklink-sdk/DeckLinkAPIVersion.h +++ b/plugins/decklink/mac/decklink-sdk/DeckLinkAPIVersion.h @@ -30,8 +30,8 @@ #ifndef __DeckLink_API_Version_h__ #define __DeckLink_API_Version_h__ -#define BLACKMAGIC_DECKLINK_API_VERSION 0x0a0b0400 -#define BLACKMAGIC_DECKLINK_API_VERSION_STRING "10.11.4" +#define BLACKMAGIC_DECKLINK_API_VERSION 0x0b060000 +#define BLACKMAGIC_DECKLINK_API_VERSION_STRING "11.6" #endif // __DeckLink_API_Version_h__ diff --git a/plugins/decklink/mac/decklink-sdk/DeckLinkAPIVideoEncoderInput_v10_11.h b/plugins/decklink/mac/decklink-sdk/DeckLinkAPIVideoEncoderInput_v10_11.h new file mode 100644 index 0000000..80921c2 --- /dev/null +++ b/plugins/decklink/mac/decklink-sdk/DeckLinkAPIVideoEncoderInput_v10_11.h @@ -0,0 +1,75 @@ +/* -LICENSE-START- +** Copyright (c) 2017 Blackmagic Design +** +** Permission is hereby granted, free of charge, to any person or organization +** obtaining a copy of the software and accompanying documentation covered by +** this license (the "Software") to use, reproduce, display, distribute, +** execute, and transmit the Software, and to prepare derivative works of the +** Software, and to permit third-parties to whom the Software is furnished to +** do so, all subject to the following: +** +** The copyright notices in the Software and this entire statement, including +** the above license grant, this restriction and the following disclaimer, +** must be included in all copies of the Software, in whole or in part, and +** all derivative works of the Software, unless such copies or derivative +** works are solely in the form of machine-executable object code generated by +** a source language processor. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +** SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +** FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +** DEALINGS IN THE SOFTWARE. +** -LICENSE-END- +*/ + +#ifndef BMD_DECKLINKAPIVIDEOENCODERINPUT_v10_11_H +#define BMD_DECKLINKAPIVIDEOENCODERINPUT_v10_11_H + +#include "DeckLinkAPI.h" +#include "DeckLinkAPI_v10_11.h" + +// Type Declarations + +BMD_CONST REFIID IID_IDeckLinkEncoderInput_v10_11 = /* 270587DA-6B7D-42E7-A1F0-6D853F581185 */ {0x27,0x05,0x87,0xDA,0x6B,0x7D,0x42,0xE7,0xA1,0xF0,0x6D,0x85,0x3F,0x58,0x11,0x85}; + +/* Interface IDeckLinkEncoderInput_v10_11 - Created by QueryInterface from IDeckLink. */ + +class IDeckLinkEncoderInput_v10_11 : public IUnknown +{ +public: + virtual HRESULT DoesSupportVideoMode (/* in */ BMDDisplayMode displayMode, /* in */ BMDPixelFormat pixelFormat, /* in */ BMDVideoInputFlags flags, /* out */ BMDDisplayModeSupport_v10_11 *result, /* out */ IDeckLinkDisplayMode **resultDisplayMode) = 0; + virtual HRESULT GetDisplayModeIterator (/* out */ IDeckLinkDisplayModeIterator **iterator) = 0; + + /* Video Input */ + + virtual HRESULT EnableVideoInput (/* in */ BMDDisplayMode displayMode, /* in */ BMDPixelFormat pixelFormat, /* in */ BMDVideoInputFlags flags) = 0; + virtual HRESULT DisableVideoInput (void) = 0; + virtual HRESULT GetAvailablePacketsCount (/* out */ uint32_t *availablePacketsCount) = 0; + virtual HRESULT SetMemoryAllocator (/* in */ IDeckLinkMemoryAllocator *theAllocator) = 0; + + /* Audio Input */ + + virtual HRESULT EnableAudioInput (/* in */ BMDAudioFormat audioFormat, /* in */ BMDAudioSampleRate sampleRate, /* in */ BMDAudioSampleType sampleType, /* in */ uint32_t channelCount) = 0; + virtual HRESULT DisableAudioInput (void) = 0; + virtual HRESULT GetAvailableAudioSampleFrameCount (/* out */ uint32_t *availableSampleFrameCount) = 0; + + /* Input Control */ + + virtual HRESULT StartStreams (void) = 0; + virtual HRESULT StopStreams (void) = 0; + virtual HRESULT PauseStreams (void) = 0; + virtual HRESULT FlushStreams (void) = 0; + virtual HRESULT SetCallback (/* in */ IDeckLinkEncoderInputCallback *theCallback) = 0; + + /* Hardware Timing */ + + virtual HRESULT GetHardwareReferenceClock (/* in */ BMDTimeScale desiredTimeScale, /* out */ BMDTimeValue *hardwareTime, /* out */ BMDTimeValue *timeInFrame, /* out */ BMDTimeValue *ticksPerFrame) = 0; + +protected: + virtual ~IDeckLinkEncoderInput_v10_11 () {} // call Release method to drop reference count +}; + +#endif /* defined(BMD_DECKLINKAPIVIDEOENCODERINPUT_v10_11_H) */ diff --git a/plugins/decklink/mac/decklink-sdk/DeckLinkAPIVideoInput_v10_11.h b/plugins/decklink/mac/decklink-sdk/DeckLinkAPIVideoInput_v10_11.h new file mode 100644 index 0000000..3751378 --- /dev/null +++ b/plugins/decklink/mac/decklink-sdk/DeckLinkAPIVideoInput_v10_11.h @@ -0,0 +1,77 @@ +/* -LICENSE-START- +** Copyright (c) 2017 Blackmagic Design +** +** Permission is hereby granted, free of charge, to any person or organization +** obtaining a copy of the software and accompanying documentation covered by +** this license (the "Software") to use, reproduce, display, distribute, +** execute, and transmit the Software, and to prepare derivative works of the +** Software, and to permit third-parties to whom the Software is furnished to +** do so, all subject to the following: +** +** The copyright notices in the Software and this entire statement, including +** the above license grant, this restriction and the following disclaimer, +** must be included in all copies of the Software, in whole or in part, and +** all derivative works of the Software, unless such copies or derivative +** works are solely in the form of machine-executable object code generated by +** a source language processor. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +** SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +** FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +** DEALINGS IN THE SOFTWARE. +** -LICENSE-END- +*/ + +#ifndef BMD_DECKLINKAPIVIDEOINPUT_v10_11_H +#define BMD_DECKLINKAPIVIDEOINPUT_v10_11_H + +#include "DeckLinkAPI.h" +#include "DeckLinkAPI_v10_11.h" + +// Type Declarations + +BMD_CONST REFIID IID_IDeckLinkInput_v10_11 = /* AF22762B-DFAC-4846-AA79-FA8883560995 */ {0xAF,0x22,0x76,0x2B,0xDF,0xAC,0x48,0x46,0xAA,0x79,0xFA,0x88,0x83,0x56,0x09,0x95}; + +/* Interface IDeckLinkInput_v10_11 - DeckLink input interface. */ + +class IDeckLinkInput_v10_11 : public IUnknown +{ +public: + virtual HRESULT DoesSupportVideoMode (/* in */ BMDDisplayMode displayMode, /* in */ BMDPixelFormat pixelFormat, /* in */ BMDVideoInputFlags flags, /* out */ BMDDisplayModeSupport_v10_11 *result, /* out */ IDeckLinkDisplayMode **resultDisplayMode) = 0; + virtual HRESULT GetDisplayModeIterator (/* out */ IDeckLinkDisplayModeIterator **iterator) = 0; + + virtual HRESULT SetScreenPreviewCallback (/* in */ IDeckLinkScreenPreviewCallback *previewCallback) = 0; + + /* Video Input */ + + virtual HRESULT EnableVideoInput (/* in */ BMDDisplayMode displayMode, /* in */ BMDPixelFormat pixelFormat, /* in */ BMDVideoInputFlags flags) = 0; + virtual HRESULT DisableVideoInput (void) = 0; + virtual HRESULT GetAvailableVideoFrameCount (/* out */ uint32_t *availableFrameCount) = 0; + virtual HRESULT SetVideoInputFrameMemoryAllocator (/* in */ IDeckLinkMemoryAllocator *theAllocator) = 0; + + /* Audio Input */ + + virtual HRESULT EnableAudioInput (/* in */ BMDAudioSampleRate sampleRate, /* in */ BMDAudioSampleType sampleType, /* in */ uint32_t channelCount) = 0; + virtual HRESULT DisableAudioInput (void) = 0; + virtual HRESULT GetAvailableAudioSampleFrameCount (/* out */ uint32_t *availableSampleFrameCount) = 0; + + /* Input Control */ + + virtual HRESULT StartStreams (void) = 0; + virtual HRESULT StopStreams (void) = 0; + virtual HRESULT PauseStreams (void) = 0; + virtual HRESULT FlushStreams (void) = 0; + virtual HRESULT SetCallback (/* in */ IDeckLinkInputCallback *theCallback) = 0; + + /* Hardware Timing */ + + virtual HRESULT GetHardwareReferenceClock (/* in */ BMDTimeScale desiredTimeScale, /* out */ BMDTimeValue *hardwareTime, /* out */ BMDTimeValue *timeInFrame, /* out */ BMDTimeValue *ticksPerFrame) = 0; + +protected: + virtual ~IDeckLinkInput_v10_11 () {} // call Release method to drop reference count +}; + +#endif /* defined(BMD_DECKLINKAPIVIDEOINPUT_v10_11_H) */ diff --git a/plugins/decklink/mac/decklink-sdk/DeckLinkAPIVideoInput_v11_4.h b/plugins/decklink/mac/decklink-sdk/DeckLinkAPIVideoInput_v11_4.h new file mode 100644 index 0000000..785302a --- /dev/null +++ b/plugins/decklink/mac/decklink-sdk/DeckLinkAPIVideoInput_v11_4.h @@ -0,0 +1,76 @@ +/* -LICENSE-START- +** Copyright (c) 2019 Blackmagic Design +** +** Permission is hereby granted, free of charge, to any person or organization +** obtaining a copy of the software and accompanying documentation covered by +** this license (the "Software") to use, reproduce, display, distribute, +** execute, and transmit the Software, and to prepare derivative works of the +** Software, and to permit third-parties to whom the Software is furnished to +** do so, all subject to the following: +** +** The copyright notices in the Software and this entire statement, including +** the above license grant, this restriction and the following disclaimer, +** must be included in all copies of the Software, in whole or in part, and +** all derivative works of the Software, unless such copies or derivative +** works are solely in the form of machine-executable object code generated by +** a source language processor. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +** SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +** FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +** DEALINGS IN THE SOFTWARE. +** -LICENSE-END- +*/ + +#ifndef BMD_DECKLINKAPIVIDEOINPUT_v11_4_H +#define BMD_DECKLINKAPIVIDEOINPUT_v11_4_H + +#include "DeckLinkAPI.h" + +// Type Declarations + +BMD_CONST REFIID IID_IDeckLinkInput_v11_4 = /* 2A88CF76-F494-4216-A7EF-DC74EEB83882 */ { 0x2A,0x88,0xCF,0x76,0xF4,0x94,0x42,0x16,0xA7,0xEF,0xDC,0x74,0xEE,0xB8,0x38,0x82 }; + +/* Interface IDeckLinkInput_v11_4 - Created by QueryInterface from IDeckLink. */ + +class BMD_PUBLIC IDeckLinkInput_v11_4 : public IUnknown +{ +public: + virtual HRESULT DoesSupportVideoMode (/* in */ BMDVideoConnection connection /* If a value of 0 is specified, the caller does not care about the connection */, /* in */ BMDDisplayMode requestedMode, /* in */ BMDPixelFormat requestedPixelFormat, /* in */ BMDSupportedVideoModeFlags flags, /* out */ bool* supported) = 0; + virtual HRESULT GetDisplayMode (/* in */ BMDDisplayMode displayMode, /* out */ IDeckLinkDisplayMode** resultDisplayMode) = 0; + virtual HRESULT GetDisplayModeIterator (/* out */ IDeckLinkDisplayModeIterator** iterator) = 0; + virtual HRESULT SetScreenPreviewCallback (/* in */ IDeckLinkScreenPreviewCallback* previewCallback) = 0; + + /* Video Input */ + + virtual HRESULT EnableVideoInput (/* in */ BMDDisplayMode displayMode, /* in */ BMDPixelFormat pixelFormat, /* in */ BMDVideoInputFlags flags) = 0; + virtual HRESULT DisableVideoInput (void) = 0; + virtual HRESULT GetAvailableVideoFrameCount (/* out */ uint32_t* availableFrameCount) = 0; + virtual HRESULT SetVideoInputFrameMemoryAllocator (/* in */ IDeckLinkMemoryAllocator* theAllocator) = 0; + + /* Audio Input */ + + virtual HRESULT EnableAudioInput (/* in */ BMDAudioSampleRate sampleRate, /* in */ BMDAudioSampleType sampleType, /* in */ uint32_t channelCount) = 0; + virtual HRESULT DisableAudioInput (void) = 0; + virtual HRESULT GetAvailableAudioSampleFrameCount (/* out */ uint32_t* availableSampleFrameCount) = 0; + + /* Input Control */ + + virtual HRESULT StartStreams (void) = 0; + virtual HRESULT StopStreams (void) = 0; + virtual HRESULT PauseStreams (void) = 0; + virtual HRESULT FlushStreams (void) = 0; + virtual HRESULT SetCallback (/* in */ IDeckLinkInputCallback* theCallback) = 0; + + /* Hardware Timing */ + + virtual HRESULT GetHardwareReferenceClock (/* in */ BMDTimeScale desiredTimeScale, /* out */ BMDTimeValue* hardwareTime, /* out */ BMDTimeValue* timeInFrame, /* out */ BMDTimeValue* ticksPerFrame) = 0; + +protected: + virtual ~IDeckLinkInput_v11_4 () {} // call Release method to drop reference count +}; + +#endif /* defined(BMD_DECKLINKAPIVIDEOINPUT_v11_4_H) */ diff --git a/plugins/decklink/mac/decklink-sdk/DeckLinkAPIVideoInput_v11_5_1.h b/plugins/decklink/mac/decklink-sdk/DeckLinkAPIVideoInput_v11_5_1.h new file mode 100644 index 0000000..cd031bd --- /dev/null +++ b/plugins/decklink/mac/decklink-sdk/DeckLinkAPIVideoInput_v11_5_1.h @@ -0,0 +1,89 @@ +/* -LICENSE-START- +** Copyright (c) 2020 Blackmagic Design +** +** Permission is hereby granted, free of charge, to any person or organization +** obtaining a copy of the software and accompanying documentation covered by +** this license (the "Software") to use, reproduce, display, distribute, +** execute, and transmit the Software, and to prepare derivative works of the +** Software, and to permit third-parties to whom the Software is furnished to +** do so, all subject to the following: +** +** The copyright notices in the Software and this entire statement, including +** the above license grant, this restriction and the following disclaimer, +** must be included in all copies of the Software, in whole or in part, and +** all derivative works of the Software, unless such copies or derivative +** works are solely in the form of machine-executable object code generated by +** a source language processor. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +** SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +** FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +** DEALINGS IN THE SOFTWARE. +** -LICENSE-END- +*/ + +#ifndef BMD_DECKLINKAPIVIDEOINPUT_v11_5_1_H +#define BMD_DECKLINKAPIVIDEOINPUT_v11_5_1_H + +#include "DeckLinkAPI.h" + +// Type Declarations + +BMD_CONST REFIID IID_IDeckLinkInputCallback_v11_5_1 = /* DD04E5EC-7415-42AB-AE4A-E80C4DFC044A */ { 0xDD, 0x04, 0xE5, 0xEC, 0x74, 0x15, 0x42, 0xAB, 0xAE, 0x4A, 0xE8, 0x0C, 0x4D, 0xFC, 0x04, 0x4A }; +BMD_CONST REFIID IID_IDeckLinkInput_v11_5_1 = /* 9434C6E4-B15D-4B1C-979E-661E3DDCB4B9 */ { 0x94, 0x34, 0xC6, 0xE4, 0xB1, 0x5D, 0x4B, 0x1C, 0x97, 0x9E, 0x66, 0x1E, 0x3D, 0xDC, 0xB4, 0xB9 }; + +/* Interface IDeckLinkInputCallback_v11_5_1 - Frame arrival callback. */ + +class BMD_PUBLIC IDeckLinkInputCallback_v11_5_1 : public IUnknown +{ +public: + virtual HRESULT VideoInputFormatChanged (/* in */ BMDVideoInputFormatChangedEvents notificationEvents, /* in */ IDeckLinkDisplayMode* newDisplayMode, /* in */ BMDDetectedVideoInputFormatFlags detectedSignalFlags) = 0; + virtual HRESULT VideoInputFrameArrived (/* in */ IDeckLinkVideoInputFrame* videoFrame, /* in */ IDeckLinkAudioInputPacket* audioPacket) = 0; + +protected: + virtual ~IDeckLinkInputCallback_v11_5_1 () {} // call Release method to drop reference count +}; + +/* Interface IDeckLinkInput_v11_5_1 - Created by QueryInterface from IDeckLink. */ + +class BMD_PUBLIC IDeckLinkInput_v11_5_1 : public IUnknown +{ +public: + virtual HRESULT DoesSupportVideoMode (/* in */ BMDVideoConnection connection /* If a value of bmdVideoConnectionUnspecified is specified, the caller does not care about the connection */, /* in */ BMDDisplayMode requestedMode, /* in */ BMDPixelFormat requestedPixelFormat, /* in */ BMDVideoInputConversionMode conversionMode, /* in */ BMDSupportedVideoModeFlags flags, /* out */ BMDDisplayMode* actualMode, /* out */ bool* supported) = 0; + virtual HRESULT GetDisplayMode (/* in */ BMDDisplayMode displayMode, /* out */ IDeckLinkDisplayMode** resultDisplayMode) = 0; + virtual HRESULT GetDisplayModeIterator (/* out */ IDeckLinkDisplayModeIterator** iterator) = 0; + virtual HRESULT SetScreenPreviewCallback (/* in */ IDeckLinkScreenPreviewCallback* previewCallback) = 0; + + /* Video Input */ + + virtual HRESULT EnableVideoInput (/* in */ BMDDisplayMode displayMode, /* in */ BMDPixelFormat pixelFormat, /* in */ BMDVideoInputFlags flags) = 0; + virtual HRESULT DisableVideoInput (void) = 0; + virtual HRESULT GetAvailableVideoFrameCount (/* out */ uint32_t* availableFrameCount) = 0; + virtual HRESULT SetVideoInputFrameMemoryAllocator (/* in */ IDeckLinkMemoryAllocator* theAllocator) = 0; + + /* Audio Input */ + + virtual HRESULT EnableAudioInput (/* in */ BMDAudioSampleRate sampleRate, /* in */ BMDAudioSampleType sampleType, /* in */ uint32_t channelCount) = 0; + virtual HRESULT DisableAudioInput (void) = 0; + virtual HRESULT GetAvailableAudioSampleFrameCount (/* out */ uint32_t* availableSampleFrameCount) = 0; + + /* Input Control */ + + virtual HRESULT StartStreams (void) = 0; + virtual HRESULT StopStreams (void) = 0; + virtual HRESULT PauseStreams (void) = 0; + virtual HRESULT FlushStreams (void) = 0; + virtual HRESULT SetCallback (/* in */ IDeckLinkInputCallback_v11_5_1* theCallback) = 0; + + /* Hardware Timing */ + + virtual HRESULT GetHardwareReferenceClock (/* in */ BMDTimeScale desiredTimeScale, /* out */ BMDTimeValue* hardwareTime, /* out */ BMDTimeValue* timeInFrame, /* out */ BMDTimeValue* ticksPerFrame) = 0; + +protected: + virtual ~IDeckLinkInput_v11_5_1 () {} // call Release method to drop reference count +}; + +#endif /* defined(BMD_DECKLINKAPIVIDEOINPUT_v11_5_1_H) */ diff --git a/plugins/decklink/mac/decklink-sdk/DeckLinkAPIVideoOutput_v10_11.h b/plugins/decklink/mac/decklink-sdk/DeckLinkAPIVideoOutput_v10_11.h new file mode 100644 index 0000000..41db8d5 --- /dev/null +++ b/plugins/decklink/mac/decklink-sdk/DeckLinkAPIVideoOutput_v10_11.h @@ -0,0 +1,95 @@ +/* -LICENSE-START- +** Copyright (c) 2017 Blackmagic Design +** +** Permission is hereby granted, free of charge, to any person or organization +** obtaining a copy of the software and accompanying documentation covered by +** this license (the "Software") to use, reproduce, display, distribute, +** execute, and transmit the Software, and to prepare derivative works of the +** Software, and to permit third-parties to whom the Software is furnished to +** do so, all subject to the following: +** +** The copyright notices in the Software and this entire statement, including +** the above license grant, this restriction and the following disclaimer, +** must be included in all copies of the Software, in whole or in part, and +** all derivative works of the Software, unless such copies or derivative +** works are solely in the form of machine-executable object code generated by +** a source language processor. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +** SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +** FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +** DEALINGS IN THE SOFTWARE. +** -LICENSE-END- +*/ + +#ifndef BMD_DECKLINKAPIVIDEOOUTPUT_v10_11_H +#define BMD_DECKLINKAPIVIDEOOUTPUT_v10_11_H + +#include "DeckLinkAPI.h" +#include "DeckLinkAPI_v10_11.h" + +// Type Declarations + +BMD_CONST REFIID IID_IDeckLinkOutput_v10_11 = /* CC5C8A6E-3F2F-4B3A-87EA-FD78AF300564 */ {0xCC,0x5C,0x8A,0x6E,0x3F,0x2F,0x4B,0x3A,0x87,0xEA,0xFD,0x78,0xAF,0x30,0x05,0x64}; + +/* Interface IDeckLinkOutput_v10_11 - DeckLink output interface. */ + +class IDeckLinkOutput_v10_11 : public IUnknown +{ +public: + virtual HRESULT DoesSupportVideoMode (/* in */ BMDDisplayMode displayMode, /* in */ BMDPixelFormat pixelFormat, /* in */ BMDVideoOutputFlags flags, /* out */ BMDDisplayModeSupport_v10_11 *result, /* out */ IDeckLinkDisplayMode **resultDisplayMode) = 0; + virtual HRESULT GetDisplayModeIterator (/* out */ IDeckLinkDisplayModeIterator **iterator) = 0; + + virtual HRESULT SetScreenPreviewCallback (/* in */ IDeckLinkScreenPreviewCallback *previewCallback) = 0; + + /* Video Output */ + + virtual HRESULT EnableVideoOutput (/* in */ BMDDisplayMode displayMode, /* in */ BMDVideoOutputFlags flags) = 0; + virtual HRESULT DisableVideoOutput (void) = 0; + + virtual HRESULT SetVideoOutputFrameMemoryAllocator (/* in */ IDeckLinkMemoryAllocator *theAllocator) = 0; + virtual HRESULT CreateVideoFrame (/* in */ int32_t width, /* in */ int32_t height, /* in */ int32_t rowBytes, /* in */ BMDPixelFormat pixelFormat, /* in */ BMDFrameFlags flags, /* out */ IDeckLinkMutableVideoFrame **outFrame) = 0; + virtual HRESULT CreateAncillaryData (/* in */ BMDPixelFormat pixelFormat, /* out */ IDeckLinkVideoFrameAncillary **outBuffer) = 0; + + virtual HRESULT DisplayVideoFrameSync (/* in */ IDeckLinkVideoFrame *theFrame) = 0; + virtual HRESULT ScheduleVideoFrame (/* in */ IDeckLinkVideoFrame *theFrame, /* in */ BMDTimeValue displayTime, /* in */ BMDTimeValue displayDuration, /* in */ BMDTimeScale timeScale) = 0; + virtual HRESULT SetScheduledFrameCompletionCallback (/* in */ IDeckLinkVideoOutputCallback *theCallback) = 0; + virtual HRESULT GetBufferedVideoFrameCount (/* out */ uint32_t *bufferedFrameCount) = 0; + + /* Audio Output */ + + virtual HRESULT EnableAudioOutput (/* in */ BMDAudioSampleRate sampleRate, /* in */ BMDAudioSampleType sampleType, /* in */ uint32_t channelCount, /* in */ BMDAudioOutputStreamType streamType) = 0; + virtual HRESULT DisableAudioOutput (void) = 0; + + virtual HRESULT WriteAudioSamplesSync (/* in */ void *buffer, /* in */ uint32_t sampleFrameCount, /* out */ uint32_t *sampleFramesWritten) = 0; + + virtual HRESULT BeginAudioPreroll (void) = 0; + virtual HRESULT EndAudioPreroll (void) = 0; + virtual HRESULT ScheduleAudioSamples (/* in */ void *buffer, /* in */ uint32_t sampleFrameCount, /* in */ BMDTimeValue streamTime, /* in */ BMDTimeScale timeScale, /* out */ uint32_t *sampleFramesWritten) = 0; + + virtual HRESULT GetBufferedAudioSampleFrameCount (/* out */ uint32_t *bufferedSampleFrameCount) = 0; + virtual HRESULT FlushBufferedAudioSamples (void) = 0; + + virtual HRESULT SetAudioCallback (/* in */ IDeckLinkAudioOutputCallback *theCallback) = 0; + + /* Output Control */ + + virtual HRESULT StartScheduledPlayback (/* in */ BMDTimeValue playbackStartTime, /* in */ BMDTimeScale timeScale, /* in */ double playbackSpeed) = 0; + virtual HRESULT StopScheduledPlayback (/* in */ BMDTimeValue stopPlaybackAtTime, /* out */ BMDTimeValue *actualStopTime, /* in */ BMDTimeScale timeScale) = 0; + virtual HRESULT IsScheduledPlaybackRunning (/* out */ bool *active) = 0; + virtual HRESULT GetScheduledStreamTime (/* in */ BMDTimeScale desiredTimeScale, /* out */ BMDTimeValue *streamTime, /* out */ double *playbackSpeed) = 0; + virtual HRESULT GetReferenceStatus (/* out */ BMDReferenceStatus *referenceStatus) = 0; + + /* Hardware Timing */ + + virtual HRESULT GetHardwareReferenceClock (/* in */ BMDTimeScale desiredTimeScale, /* out */ BMDTimeValue *hardwareTime, /* out */ BMDTimeValue *timeInFrame, /* out */ BMDTimeValue *ticksPerFrame) = 0; + virtual HRESULT GetFrameCompletionReferenceTimestamp (/* in */ IDeckLinkVideoFrame *theFrame, /* in */ BMDTimeScale desiredTimeScale, /* out */ BMDTimeValue *frameCompletionTimestamp) = 0; + +protected: + virtual ~IDeckLinkOutput_v10_11 () {} // call Release method to drop reference count +}; + +#endif /* defined(BMD_DECKLINKAPIVIDEOOUTPUT_v10_11_H) */ diff --git a/plugins/decklink/mac/decklink-sdk/DeckLinkAPIVideoOutput_v11_4.h b/plugins/decklink/mac/decklink-sdk/DeckLinkAPIVideoOutput_v11_4.h new file mode 100644 index 0000000..6ce584d --- /dev/null +++ b/plugins/decklink/mac/decklink-sdk/DeckLinkAPIVideoOutput_v11_4.h @@ -0,0 +1,88 @@ +/* -LICENSE-START- +** Copyright (c) 2019 Blackmagic Design +** +** Permission is hereby granted, free of charge, to any person or organization +** obtaining a copy of the software and accompanying documentation covered by +** this license (the "Software") to use, reproduce, display, distribute, +** execute, and transmit the Software, and to prepare derivative works of the +** Software, and to permit third-parties to whom the Software is furnished to +** do so, all subject to the following: +** +** The copyright notices in the Software and this entire statement, including +** the above license grant, this restriction and the following disclaimer, +** must be included in all copies of the Software, in whole or in part, and +** all derivative works of the Software, unless such copies or derivative +** works are solely in the form of machine-executable object code generated by +** a source language processor. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +** SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +** FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +** DEALINGS IN THE SOFTWARE. +** -LICENSE-END- +*/ + +#ifndef BMD_DECKLINKAPIVIDEOOUTPUT_v11_4_H +#define BMD_DECKLINKAPIVIDEOOUTPUT_v11_4_H + +#include "DeckLinkAPI.h" + +// Type Declarations + +BMD_CONST REFIID IID_IDeckLinkOutput_v11_4 = /* 065A0F6C-C508-4D0D-B919-F5EB0EBFC96B */ { 0x06,0x5A,0x0F,0x6C,0xC5,0x08,0x4D,0x0D,0xB9,0x19,0xF5,0xEB,0x0E,0xBF,0xC9,0x6B }; + +/* Interface IDeckLinkOutput_v11_4 - Created by QueryInterface from IDeckLink. */ + +class BMD_PUBLIC IDeckLinkOutput_v11_4 : public IUnknown +{ +public: + virtual HRESULT DoesSupportVideoMode (/* in */ BMDVideoConnection connection /* If a value of 0 is specified, the caller does not care about the connection */, /* in */ BMDDisplayMode requestedMode, /* in */ BMDPixelFormat requestedPixelFormat, /* in */ BMDSupportedVideoModeFlags flags, /* out */ BMDDisplayMode* actualMode, /* out */ bool* supported) = 0; + virtual HRESULT GetDisplayMode (/* in */ BMDDisplayMode displayMode, /* out */ IDeckLinkDisplayMode** resultDisplayMode) = 0; + virtual HRESULT GetDisplayModeIterator (/* out */ IDeckLinkDisplayModeIterator** iterator) = 0; + virtual HRESULT SetScreenPreviewCallback (/* in */ IDeckLinkScreenPreviewCallback* previewCallback) = 0; + + /* Video Output */ + + virtual HRESULT EnableVideoOutput (/* in */ BMDDisplayMode displayMode, /* in */ BMDVideoOutputFlags flags) = 0; + virtual HRESULT DisableVideoOutput (void) = 0; + virtual HRESULT SetVideoOutputFrameMemoryAllocator (/* in */ IDeckLinkMemoryAllocator* theAllocator) = 0; + virtual HRESULT CreateVideoFrame (/* in */ int32_t width, /* in */ int32_t height, /* in */ int32_t rowBytes, /* in */ BMDPixelFormat pixelFormat, /* in */ BMDFrameFlags flags, /* out */ IDeckLinkMutableVideoFrame** outFrame) = 0; + virtual HRESULT CreateAncillaryData (/* in */ BMDPixelFormat pixelFormat, /* out */ IDeckLinkVideoFrameAncillary** outBuffer) = 0; // Use of IDeckLinkVideoFrameAncillaryPackets is preferred + virtual HRESULT DisplayVideoFrameSync (/* in */ IDeckLinkVideoFrame* theFrame) = 0; + virtual HRESULT ScheduleVideoFrame (/* in */ IDeckLinkVideoFrame* theFrame, /* in */ BMDTimeValue displayTime, /* in */ BMDTimeValue displayDuration, /* in */ BMDTimeScale timeScale) = 0; + virtual HRESULT SetScheduledFrameCompletionCallback (/* in */ IDeckLinkVideoOutputCallback* theCallback) = 0; + virtual HRESULT GetBufferedVideoFrameCount (/* out */ uint32_t* bufferedFrameCount) = 0; + + /* Audio Output */ + + virtual HRESULT EnableAudioOutput (/* in */ BMDAudioSampleRate sampleRate, /* in */ BMDAudioSampleType sampleType, /* in */ uint32_t channelCount, /* in */ BMDAudioOutputStreamType streamType) = 0; + virtual HRESULT DisableAudioOutput (void) = 0; + virtual HRESULT WriteAudioSamplesSync (/* in */ void* buffer, /* in */ uint32_t sampleFrameCount, /* out */ uint32_t* sampleFramesWritten) = 0; + virtual HRESULT BeginAudioPreroll (void) = 0; + virtual HRESULT EndAudioPreroll (void) = 0; + virtual HRESULT ScheduleAudioSamples (/* in */ void* buffer, /* in */ uint32_t sampleFrameCount, /* in */ BMDTimeValue streamTime, /* in */ BMDTimeScale timeScale, /* out */ uint32_t* sampleFramesWritten) = 0; + virtual HRESULT GetBufferedAudioSampleFrameCount (/* out */ uint32_t* bufferedSampleFrameCount) = 0; + virtual HRESULT FlushBufferedAudioSamples (void) = 0; + virtual HRESULT SetAudioCallback (/* in */ IDeckLinkAudioOutputCallback* theCallback) = 0; + + /* Output Control */ + + virtual HRESULT StartScheduledPlayback (/* in */ BMDTimeValue playbackStartTime, /* in */ BMDTimeScale timeScale, /* in */ double playbackSpeed) = 0; + virtual HRESULT StopScheduledPlayback (/* in */ BMDTimeValue stopPlaybackAtTime, /* out */ BMDTimeValue* actualStopTime, /* in */ BMDTimeScale timeScale) = 0; + virtual HRESULT IsScheduledPlaybackRunning (/* out */ bool* active) = 0; + virtual HRESULT GetScheduledStreamTime (/* in */ BMDTimeScale desiredTimeScale, /* out */ BMDTimeValue* streamTime, /* out */ double* playbackSpeed) = 0; + virtual HRESULT GetReferenceStatus (/* out */ BMDReferenceStatus* referenceStatus) = 0; + + /* Hardware Timing */ + + virtual HRESULT GetHardwareReferenceClock (/* in */ BMDTimeScale desiredTimeScale, /* out */ BMDTimeValue* hardwareTime, /* out */ BMDTimeValue* timeInFrame, /* out */ BMDTimeValue* ticksPerFrame) = 0; + virtual HRESULT GetFrameCompletionReferenceTimestamp (/* in */ IDeckLinkVideoFrame* theFrame, /* in */ BMDTimeScale desiredTimeScale, /* out */ BMDTimeValue* frameCompletionTimestamp) = 0; + +protected: + virtual ~IDeckLinkOutput_v11_4 () {} // call Release method to drop reference count +}; + +#endif /* defined(BMD_DECKLINKAPIVIDEOOUTPUT_v11_4_H) */ diff --git a/plugins/decklink/mac/decklink-sdk/DeckLinkAPI_v10_11.h b/plugins/decklink/mac/decklink-sdk/DeckLinkAPI_v10_11.h new file mode 100644 index 0000000..70a372e --- /dev/null +++ b/plugins/decklink/mac/decklink-sdk/DeckLinkAPI_v10_11.h @@ -0,0 +1,122 @@ +/* -LICENSE-START- +** Copyright (c) 2018 Blackmagic Design +** +** Permission is hereby granted, free of charge, to any person or organization +** obtaining a copy of the software and accompanying documentation covered by +** this license (the "Software") to use, reproduce, display, distribute, +** execute, and transmit the Software, and to prepare derivative works of the +** Software, and to permit third-parties to whom the Software is furnished to +** do so, all subject to the following: +** +** The copyright notices in the Software and this entire statement, including +** the above license grant, this restriction and the following disclaimer, +** must be included in all copies of the Software, in whole or in part, and +** all derivative works of the Software, unless such copies or derivative +** works are solely in the form of machine-executable object code generated by +** a source language processor. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +** SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +** FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +** DEALINGS IN THE SOFTWARE. +** -LICENSE-END- +*/ + +#ifndef BMD_DECKLINKAPI_v10_11_H +#define BMD_DECKLINKAPI_v10_11_H + +#include "DeckLinkAPI.h" + +// Interface ID Declarations + +BMD_CONST REFIID IID_IDeckLinkAttributes_v10_11 = /* ABC11843-D966-44CB-96E2-A1CB5D3135C4 */ {0xAB,0xC1,0x18,0x43,0xD9,0x66,0x44,0xCB,0x96,0xE2,0xA1,0xCB,0x5D,0x31,0x35,0xC4}; +BMD_CONST REFIID IID_IDeckLinkNotification_v10_11 = /* 0A1FB207-E215-441B-9B19-6FA1575946C5 */ {0x0A,0x1F,0xB2,0x07,0xE2,0x15,0x44,0x1B,0x9B,0x19,0x6F,0xA1,0x57,0x59,0x46,0xC5}; + +/* Enum BMDDisplayModeSupport_v10_11 - Output mode supported flags */ + +typedef uint32_t BMDDisplayModeSupport_v10_11; +enum _BMDDisplayModeSupport_v10_11 { + bmdDisplayModeNotSupported_v10_11 = 0, + bmdDisplayModeSupported_v10_11, + bmdDisplayModeSupportedWithConversion_v10_11 +}; + +/* Enum BMDDuplexMode_v10_11 - Duplex for configurable ports */ + +typedef uint32_t BMDDuplexMode_v10_11; +enum _BMDDuplexMode_v10_11 { + bmdDuplexModeFull_v10_11 = 'fdup', + bmdDuplexModeHalf_v10_11 = 'hdup' +}; + +/* Enum BMDDeckLinkAttributeID_v10_11 - DeckLink Attribute ID */ + +enum _BMDDeckLinkAttributeID_v10_11 { + + /* Flags */ + + BMDDeckLinkSupportsDuplexModeConfiguration_v10_11 = 'dupx', + BMDDeckLinkSupportsHDKeying_v10_11 = 'keyh', + + /* Integers */ + + BMDDeckLinkPairedDevicePersistentID_v10_11 = 'ppid', + BMDDeckLinkSupportsFullDuplex_v10_11 = 'fdup', +}; + +enum _BMDDeckLinkStatusID_v10_11 { + bmdDeckLinkStatusDuplexMode_v10_11 = 'dupx', +}; + +typedef uint32_t BMDDuplexStatus_v10_11; +enum _BMDDuplexStatus_v10_11 { + bmdDuplexFullDuplex_v10_11 = 'fdup', + bmdDuplexHalfDuplex_v10_11 = 'hdup', + bmdDuplexSimplex_v10_11 = 'splx', + bmdDuplexInactive_v10_11 = 'inac', +}; + +#if defined(__cplusplus) + +/* Interface IDeckLinkAttributes_v10_11 - DeckLink Attribute interface */ + +class BMD_PUBLIC IDeckLinkAttributes_v10_11 : public IUnknown +{ +public: + virtual HRESULT GetFlag (/* in */ BMDDeckLinkAttributeID cfgID, /* out */ bool *value) = 0; + virtual HRESULT GetInt (/* in */ BMDDeckLinkAttributeID cfgID, /* out */ int64_t *value) = 0; + virtual HRESULT GetFloat (/* in */ BMDDeckLinkAttributeID cfgID, /* out */ double *value) = 0; + virtual HRESULT GetString (/* in */ BMDDeckLinkAttributeID cfgID, /* out */ CFStringRef *value) = 0; + +protected: + virtual ~IDeckLinkAttributes_v10_11 () {} // call Release method to drop reference count +}; + +/* Interface IDeckLinkNotification_v10_11 - DeckLink Notification interface */ + +class BMD_PUBLIC IDeckLinkNotification_v10_11 : public IUnknown +{ +public: + virtual HRESULT Subscribe (/* in */ BMDNotifications topic, /* in */ IDeckLinkNotificationCallback *theCallback) = 0; + virtual HRESULT Unsubscribe (/* in */ BMDNotifications topic, /* in */ IDeckLinkNotificationCallback *theCallback) = 0; +}; + +/* Functions */ + +extern "C" { + + IDeckLinkIterator* BMD_PUBLIC CreateDeckLinkIteratorInstance_v10_11 (void); + IDeckLinkDiscovery* BMD_PUBLIC CreateDeckLinkDiscoveryInstance_v10_11 (void); + IDeckLinkAPIInformation* BMD_PUBLIC CreateDeckLinkAPIInformationInstance_v10_11 (void); + IDeckLinkGLScreenPreviewHelper* BMD_PUBLIC CreateOpenGLScreenPreviewHelper_v10_11 (void); + IDeckLinkCocoaScreenPreviewCallback* BMD_PUBLIC CreateCocoaScreenPreview_v10_11 (void* /* (NSView*) */ parentView); + IDeckLinkVideoConversion* BMD_PUBLIC CreateVideoConversionInstance_v10_11 (void); + IDeckLinkVideoFrameAncillaryPackets* BMD_PUBLIC CreateVideoFrameAncillaryPacketsInstance_v10_11 (void); // For use when creating a custom IDeckLinkVideoFrame without wrapping IDeckLinkOutput::CreateVideoFrame + +} + +#endif // defined(__cplusplus) +#endif /* defined(BMD_DECKLINKAPI_v10_11_H) */ diff --git a/plugins/decklink/mac/decklink-sdk/DeckLinkAPI_v11_5.h b/plugins/decklink/mac/decklink-sdk/DeckLinkAPI_v11_5.h new file mode 100644 index 0000000..01b74fa --- /dev/null +++ b/plugins/decklink/mac/decklink-sdk/DeckLinkAPI_v11_5.h @@ -0,0 +1,100 @@ +/* -LICENSE-START- +** Copyright (c) 2020 Blackmagic Design +** +** Permission is hereby granted, free of charge, to any person or organization +** obtaining a copy of the software and accompanying documentation covered by +** this license (the "Software") to use, reproduce, display, distribute, +** execute, and transmit the Software, and to prepare derivative works of the +** Software, and to permit third-parties to whom the Software is furnished to +** do so, all subject to the following: +** +** The copyright notices in the Software and this entire statement, including +** the above license grant, this restriction and the following disclaimer, +** must be included in all copies of the Software, in whole or in part, and +** all derivative works of the Software, unless such copies or derivative +** works are solely in the form of machine-executable object code generated by +** a source language processor. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +** SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +** FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +** DEALINGS IN THE SOFTWARE. +** -LICENSE-END- +*/ + +#ifndef BMD_DECKLINKAPI_v11_5_H +#define BMD_DECKLINKAPI_v11_5_H + +#include "DeckLinkAPI.h" + +BMD_CONST REFIID IID_IDeckLinkVideoFrameMetadataExtensions_v11_5 = /* D5973DC9-6432-46D0-8F0B-2496F8A1238F */ {0xD5,0x97,0x3D,0xC9,0x64,0x32,0x46,0xD0,0x8F,0x0B,0x24,0x96,0xF8,0xA1,0x23,0x8F}; + +/* Enum BMDDeckLinkFrameMetadataID - DeckLink Frame Metadata ID */ + +typedef uint32_t BMDDeckLinkFrameMetadataID_v11_5; +enum _BMDDeckLinkFrameMetadataID_v11_5 { + bmdDeckLinkFrameMetadataCintelFilmType_v11_5 = /* 'cfty' */ 0x63667479, // Current film type + bmdDeckLinkFrameMetadataCintelFilmGauge_v11_5 = /* 'cfga' */ 0x63666761, // Current film gauge + bmdDeckLinkFrameMetadataCintelKeykodeLow_v11_5 = /* 'ckkl' */ 0x636B6B6C, // Raw keykode value - low 64 bits + bmdDeckLinkFrameMetadataCintelKeykodeHigh_v11_5 = /* 'ckkh' */ 0x636B6B68, // Raw keykode value - high 64 bits + bmdDeckLinkFrameMetadataCintelTile1Size_v11_5 = /* 'ct1s' */ 0x63743173, // Size in bytes of compressed raw tile 1 + bmdDeckLinkFrameMetadataCintelTile2Size_v11_5 = /* 'ct2s' */ 0x63743273, // Size in bytes of compressed raw tile 2 + bmdDeckLinkFrameMetadataCintelTile3Size_v11_5 = /* 'ct3s' */ 0x63743373, // Size in bytes of compressed raw tile 3 + bmdDeckLinkFrameMetadataCintelTile4Size_v11_5 = /* 'ct4s' */ 0x63743473, // Size in bytes of compressed raw tile 4 + bmdDeckLinkFrameMetadataCintelImageWidth_v11_5 = /* 'IWPx' */ 0x49575078, // Width in pixels of image + bmdDeckLinkFrameMetadataCintelImageHeight_v11_5 = /* 'IHPx' */ 0x49485078, // Height in pixels of image + bmdDeckLinkFrameMetadataCintelLinearMaskingRedInRed_v11_5 = /* 'mrir' */ 0x6D726972, // Red in red linear masking parameter + bmdDeckLinkFrameMetadataCintelLinearMaskingGreenInRed_v11_5 = /* 'mgir' */ 0x6D676972, // Green in red linear masking parameter + bmdDeckLinkFrameMetadataCintelLinearMaskingBlueInRed_v11_5 = /* 'mbir' */ 0x6D626972, // Blue in red linear masking parameter + bmdDeckLinkFrameMetadataCintelLinearMaskingRedInGreen_v11_5 = /* 'mrig' */ 0x6D726967, // Red in green linear masking parameter + bmdDeckLinkFrameMetadataCintelLinearMaskingGreenInGreen_v11_5 = /* 'mgig' */ 0x6D676967, // Green in green linear masking parameter + bmdDeckLinkFrameMetadataCintelLinearMaskingBlueInGreen_v11_5 = /* 'mbig' */ 0x6D626967, // Blue in green linear masking parameter + bmdDeckLinkFrameMetadataCintelLinearMaskingRedInBlue_v11_5 = /* 'mrib' */ 0x6D726962, // Red in blue linear masking parameter + bmdDeckLinkFrameMetadataCintelLinearMaskingGreenInBlue_v11_5 = /* 'mgib' */ 0x6D676962, // Green in blue linear masking parameter + bmdDeckLinkFrameMetadataCintelLinearMaskingBlueInBlue_v11_5 = /* 'mbib' */ 0x6D626962, // Blue in blue linear masking parameter + bmdDeckLinkFrameMetadataCintelLogMaskingRedInRed_v11_5 = /* 'mlrr' */ 0x6D6C7272, // Red in red log masking parameter + bmdDeckLinkFrameMetadataCintelLogMaskingGreenInRed_v11_5 = /* 'mlgr' */ 0x6D6C6772, // Green in red log masking parameter + bmdDeckLinkFrameMetadataCintelLogMaskingBlueInRed_v11_5 = /* 'mlbr' */ 0x6D6C6272, // Blue in red log masking parameter + bmdDeckLinkFrameMetadataCintelLogMaskingRedInGreen_v11_5 = /* 'mlrg' */ 0x6D6C7267, // Red in green log masking parameter + bmdDeckLinkFrameMetadataCintelLogMaskingGreenInGreen_v11_5 = /* 'mlgg' */ 0x6D6C6767, // Green in green log masking parameter + bmdDeckLinkFrameMetadataCintelLogMaskingBlueInGreen_v11_5 = /* 'mlbg' */ 0x6D6C6267, // Blue in green log masking parameter + bmdDeckLinkFrameMetadataCintelLogMaskingRedInBlue_v11_5 = /* 'mlrb' */ 0x6D6C7262, // Red in blue log masking parameter + bmdDeckLinkFrameMetadataCintelLogMaskingGreenInBlue_v11_5 = /* 'mlgb' */ 0x6D6C6762, // Green in blue log masking parameter + bmdDeckLinkFrameMetadataCintelLogMaskingBlueInBlue_v11_5 = /* 'mlbb' */ 0x6D6C6262, // Blue in blue log masking parameter + bmdDeckLinkFrameMetadataCintelFilmFrameRate_v11_5 = /* 'cffr' */ 0x63666672, // Film frame rate + bmdDeckLinkFrameMetadataCintelOffsetToApplyHorizontal_v11_5 = /* 'otah' */ 0x6F746168, // Horizontal offset (pixels) to be applied to image + bmdDeckLinkFrameMetadataCintelOffsetToApplyVertical_v11_5 = /* 'otav' */ 0x6F746176, // Vertical offset (pixels) to be applied to image + bmdDeckLinkFrameMetadataCintelGainRed_v11_5 = /* 'LfRd' */ 0x4C665264, // Red gain parameter to apply after log + bmdDeckLinkFrameMetadataCintelGainGreen_v11_5 = /* 'LfGr' */ 0x4C664772, // Green gain parameter to apply after log + bmdDeckLinkFrameMetadataCintelGainBlue_v11_5 = /* 'LfBl' */ 0x4C66426C, // Blue gain parameter to apply after log + bmdDeckLinkFrameMetadataCintelLiftRed_v11_5 = /* 'GnRd' */ 0x476E5264, // Red lift parameter to apply after log and gain + bmdDeckLinkFrameMetadataCintelLiftGreen_v11_5 = /* 'GnGr' */ 0x476E4772, // Green lift parameter to apply after log and gain + bmdDeckLinkFrameMetadataCintelLiftBlue_v11_5 = /* 'GnBl' */ 0x476E426C, // Blue lift parameter to apply after log and gain + bmdDeckLinkFrameMetadataCintelHDRGainRed_v11_5 = /* 'HGRd' */ 0x48475264, // Red gain parameter to apply to linear data for HDR Combination + bmdDeckLinkFrameMetadataCintelHDRGainGreen_v11_5 = /* 'HGGr' */ 0x48474772, // Green gain parameter to apply to linear data for HDR Combination + bmdDeckLinkFrameMetadataCintelHDRGainBlue_v11_5 = /* 'HGBl' */ 0x4847426C, // Blue gain parameter to apply to linear data for HDR Combination + bmdDeckLinkFrameMetadataCintel16mmCropRequired_v11_5 = /* 'c16c' */ 0x63313663, // The image should be cropped to 16mm size + bmdDeckLinkFrameMetadataCintelInversionRequired_v11_5 = /* 'cinv' */ 0x63696E76, // The image should be colour inverted + bmdDeckLinkFrameMetadataCintelFlipRequired_v11_5 = /* 'cflr' */ 0x63666C72, // The image should be flipped horizontally + bmdDeckLinkFrameMetadataCintelFocusAssistEnabled_v11_5 = /* 'cfae' */ 0x63666165, // Focus Assist is currently enabled + bmdDeckLinkFrameMetadataCintelKeykodeIsInterpolated_v11_5 = /* 'kkii' */ 0x6B6B6969 // The keykode for this frame is interpolated from nearby keykodes +}; + +/* Interface IDeckLinkVideoFrameMetadataExtensions - Optional interface implemented on IDeckLinkVideoFrame to support frame metadata such as HDMI HDR information */ + +class BMD_PUBLIC IDeckLinkVideoFrameMetadataExtensions_v11_5 : public IUnknown +{ +public: + virtual HRESULT GetInt (/* in */ BMDDeckLinkFrameMetadataID_v11_5 metadataID, /* out */ int64_t *value) = 0; + virtual HRESULT GetFloat (/* in */ BMDDeckLinkFrameMetadataID_v11_5 metadataID, /* out */ double *value) = 0; + virtual HRESULT GetFlag (/* in */ BMDDeckLinkFrameMetadataID_v11_5 metadataID, /* out */ bool *value) = 0; + virtual HRESULT GetString (/* in */ BMDDeckLinkFrameMetadataID_v11_5 metadataID, /* out */ CFStringRef *value) = 0; + +protected: + virtual ~IDeckLinkVideoFrameMetadataExtensions_v11_5 () {} // call Release method to drop reference count +}; + +#endif /* defined(BMD_DECKLINKAPI_v11_5_H) */ diff --git a/plugins/decklink/mac/decklink-sdk/DeckLinkAPI_v11_5_1.h b/plugins/decklink/mac/decklink-sdk/DeckLinkAPI_v11_5_1.h new file mode 100644 index 0000000..71ca171 --- /dev/null +++ b/plugins/decklink/mac/decklink-sdk/DeckLinkAPI_v11_5_1.h @@ -0,0 +1,44 @@ +/* -LICENSE-START- +** Copyright (c) 2020 Blackmagic Design +** +** Permission is hereby granted, free of charge, to any person or organization +** obtaining a copy of the software and accompanying documentation covered by +** this license (the "Software") to use, reproduce, display, distribute, +** execute, and transmit the Software, and to prepare derivative works of the +** Software, and to permit third-parties to whom the Software is furnished to +** do so, all subject to the following: +** +** The copyright notices in the Software and this entire statement, including +** the above license grant, this restriction and the following disclaimer, +** must be included in all copies of the Software, in whole or in part, and +** all derivative works of the Software, unless such copies or derivative +** works are solely in the form of machine-executable object code generated by +** a source language processor. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +** SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +** FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +** DEALINGS IN THE SOFTWARE. +** -LICENSE-END- +*/ + +#ifndef BMD_DECKLINKAPI_v11_5_1_H +#define BMD_DECKLINKAPI_v11_5_1_H + +#include "DeckLinkAPI.h" + +/* Enum BMDDeckLinkStatusID - DeckLink Status ID */ + +typedef uint32_t BMDDeckLinkStatusID_v11_5_1; +enum _BMDDeckLinkStatusID_v11_5_1 { + + /* Video output flags */ + + bmdDeckLinkStatusDetectedVideoInputFlags_v11_5_1 = /* 'dvif' */ 0x64766966, + +}; + +#endif /* defined(BMD_DECKLINKAPI_v11_5_1_H) */ diff --git a/plugins/decklink/mac/decklink-sdk/DeckLinkAPI_v7_1.h b/plugins/decklink/mac/decklink-sdk/DeckLinkAPI_v7_1.h index 68d0beb..8e38f07 100644 --- a/plugins/decklink/mac/decklink-sdk/DeckLinkAPI_v7_1.h +++ b/plugins/decklink/mac/decklink-sdk/DeckLinkAPI_v7_1.h @@ -30,6 +30,7 @@ #define __DeckLink_API_v7_1_h__ #include "DeckLinkAPI.h" +#include "DeckLinkAPI_v10_11.h" // "B28131B6-59AC-4857-B5AC-CD75D5883E2F" #define IID_IDeckLinkDisplayModeIterator_v7_1 (REFIID){0xB2,0x81,0x31,0xB6,0x59,0xAC,0x48,0x57,0xB5,0xAC,0xCD,0x75,0xD5,0x88,0x3E,0x2F} @@ -100,7 +101,7 @@ class IDeckLinkOutput_v7_1 : public IUnknown { public: // Display mode predicates - virtual HRESULT STDMETHODCALLTYPE DoesSupportVideoMode (BMDDisplayMode displayMode, BMDPixelFormat pixelFormat, BMDDisplayModeSupport *result) = 0; + virtual HRESULT STDMETHODCALLTYPE DoesSupportVideoMode (BMDDisplayMode displayMode, BMDPixelFormat pixelFormat, BMDDisplayModeSupport_v10_11 *result) = 0; virtual HRESULT STDMETHODCALLTYPE GetDisplayModeIterator (IDeckLinkDisplayModeIterator_v7_1* *iterator) = 0; @@ -143,7 +144,7 @@ public: class IDeckLinkInput_v7_1 : public IUnknown { public: - virtual HRESULT STDMETHODCALLTYPE DoesSupportVideoMode (BMDDisplayMode displayMode, BMDPixelFormat pixelFormat, BMDDisplayModeSupport *result) = 0; + virtual HRESULT STDMETHODCALLTYPE DoesSupportVideoMode (BMDDisplayMode displayMode, BMDPixelFormat pixelFormat, BMDDisplayModeSupport_v10_11 *result) = 0; virtual HRESULT STDMETHODCALLTYPE GetDisplayModeIterator (IDeckLinkDisplayModeIterator_v7_1 **iterator) = 0; // Video input diff --git a/plugins/decklink/mac/decklink-sdk/DeckLinkAPI_v7_3.h b/plugins/decklink/mac/decklink-sdk/DeckLinkAPI_v7_3.h index 430a905..a0232b3 100644 --- a/plugins/decklink/mac/decklink-sdk/DeckLinkAPI_v7_3.h +++ b/plugins/decklink/mac/decklink-sdk/DeckLinkAPI_v7_3.h @@ -56,7 +56,7 @@ class IDeckLinkVideoInputFrame_v7_3; class IDeckLinkOutput_v7_3 : public IUnknown { public: - virtual HRESULT DoesSupportVideoMode (BMDDisplayMode displayMode, BMDPixelFormat pixelFormat, /* out */ BMDDisplayModeSupport *result) = 0; + virtual HRESULT DoesSupportVideoMode (BMDDisplayMode displayMode, BMDPixelFormat pixelFormat, /* out */ BMDDisplayModeSupport_v10_11 *result) = 0; virtual HRESULT GetDisplayModeIterator (/* out */ IDeckLinkDisplayModeIterator_v7_6 **iterator) = 0; virtual HRESULT SetScreenPreviewCallback (/* in */ IDeckLinkScreenPreviewCallback *previewCallback) = 0; @@ -125,7 +125,7 @@ protected: class IDeckLinkInput_v7_3 : public IUnknown { public: - virtual HRESULT DoesSupportVideoMode (BMDDisplayMode displayMode, BMDPixelFormat pixelFormat, /* out */ BMDDisplayModeSupport *result) = 0; + virtual HRESULT DoesSupportVideoMode (BMDDisplayMode displayMode, BMDPixelFormat pixelFormat, /* out */ BMDDisplayModeSupport_v10_11 *result) = 0; virtual HRESULT GetDisplayModeIterator (/* out */ IDeckLinkDisplayModeIterator_v7_6 **iterator) = 0; virtual HRESULT SetScreenPreviewCallback (/* in */ IDeckLinkScreenPreviewCallback *previewCallback) = 0; diff --git a/plugins/decklink/mac/decklink-sdk/DeckLinkAPI_v7_6.h b/plugins/decklink/mac/decklink-sdk/DeckLinkAPI_v7_6.h index a90d497..45505c4 100644 --- a/plugins/decklink/mac/decklink-sdk/DeckLinkAPI_v7_6.h +++ b/plugins/decklink/mac/decklink-sdk/DeckLinkAPI_v7_6.h @@ -31,6 +31,7 @@ #define __DeckLink_API_v7_6_h__ #include "DeckLinkAPI.h" +#include "DeckLinkAPI_v10_11.h" // Interface ID Declarations @@ -144,7 +145,7 @@ protected: class IDeckLinkOutput_v7_6 : public IUnknown { public: - virtual HRESULT DoesSupportVideoMode (/* in */ BMDDisplayMode displayMode, /* in */ BMDPixelFormat pixelFormat, /* out */ BMDDisplayModeSupport *result) = 0; + virtual HRESULT DoesSupportVideoMode (/* in */ BMDDisplayMode displayMode, /* in */ BMDPixelFormat pixelFormat, /* out */ BMDDisplayModeSupport_v10_11 *result) = 0; virtual HRESULT GetDisplayModeIterator (/* out */ IDeckLinkDisplayModeIterator_v7_6 **iterator) = 0; virtual HRESULT SetScreenPreviewCallback (/* in */ IDeckLinkScreenPreviewCallback_v7_6 *previewCallback) = 0; @@ -200,7 +201,7 @@ protected: class IDeckLinkInput_v7_6 : public IUnknown { public: - virtual HRESULT DoesSupportVideoMode (/* in */ BMDDisplayMode displayMode, /* in */ BMDPixelFormat pixelFormat, /* out */ BMDDisplayModeSupport *result) = 0; + virtual HRESULT DoesSupportVideoMode (/* in */ BMDDisplayMode displayMode, /* in */ BMDPixelFormat pixelFormat, /* out */ BMDDisplayModeSupport_v10_11 *result) = 0; virtual HRESULT GetDisplayModeIterator (/* out */ IDeckLinkDisplayModeIterator_v7_6 **iterator) = 0; virtual HRESULT SetScreenPreviewCallback (/* in */ IDeckLinkScreenPreviewCallback_v7_6 *previewCallback) = 0; diff --git a/plugins/decklink/mac/decklink-sdk/DeckLinkAPI_v9_2.h b/plugins/decklink/mac/decklink-sdk/DeckLinkAPI_v9_2.h index ab2aa03..e1c9302 100644 --- a/plugins/decklink/mac/decklink-sdk/DeckLinkAPI_v9_2.h +++ b/plugins/decklink/mac/decklink-sdk/DeckLinkAPI_v9_2.h @@ -29,6 +29,7 @@ #define BMD_DECKLINKAPI_v9_2_H #include "DeckLinkAPI.h" +#include "DeckLinkAPI_v10_11.h" // Interface ID Declarations @@ -43,7 +44,7 @@ class IDeckLinkInput_v9_2 : public IUnknown { public: - virtual HRESULT DoesSupportVideoMode (/* in */ BMDDisplayMode displayMode, /* in */ BMDPixelFormat pixelFormat, /* in */ BMDVideoInputFlags flags, /* out */ BMDDisplayModeSupport *result, /* out */ IDeckLinkDisplayMode **resultDisplayMode) = 0; + virtual HRESULT DoesSupportVideoMode (/* in */ BMDDisplayMode displayMode, /* in */ BMDPixelFormat pixelFormat, /* in */ BMDVideoInputFlags flags, /* out */ BMDDisplayModeSupport_v10_11 *result, /* out */ IDeckLinkDisplayMode **resultDisplayMode) = 0; virtual HRESULT GetDisplayModeIterator (/* out */ IDeckLinkDisplayModeIterator **iterator) = 0; virtual HRESULT SetScreenPreviewCallback (/* in */ IDeckLinkScreenPreviewCallback *previewCallback) = 0; diff --git a/plugins/decklink/mac/decklink-sdk/DeckLinkAPI_v9_9.h b/plugins/decklink/mac/decklink-sdk/DeckLinkAPI_v9_9.h index 966c8ad..751cc73 100644 --- a/plugins/decklink/mac/decklink-sdk/DeckLinkAPI_v9_9.h +++ b/plugins/decklink/mac/decklink-sdk/DeckLinkAPI_v9_9.h @@ -29,6 +29,7 @@ #define BMD_DECKLINKAPI_v9_9_H #include "DeckLinkAPI.h" +#include "DeckLinkAPI_v10_11.h" // Interface ID Declarations @@ -45,7 +46,7 @@ class IDeckLinkOutput_v9_9; class IDeckLinkOutput_v9_9 : public IUnknown { public: - virtual HRESULT DoesSupportVideoMode (/* in */ BMDDisplayMode displayMode, /* in */ BMDPixelFormat pixelFormat, /* in */ BMDVideoOutputFlags flags, /* out */ BMDDisplayModeSupport *result, /* out */ IDeckLinkDisplayMode **resultDisplayMode) = 0; + virtual HRESULT DoesSupportVideoMode (/* in */ BMDDisplayMode displayMode, /* in */ BMDPixelFormat pixelFormat, /* in */ BMDVideoOutputFlags flags, /* out */ BMDDisplayModeSupport_v10_11 *result, /* out */ IDeckLinkDisplayMode **resultDisplayMode) = 0; virtual HRESULT GetDisplayModeIterator (/* out */ IDeckLinkDisplayModeIterator **iterator) = 0; virtual HRESULT SetScreenPreviewCallback (/* in */ IDeckLinkScreenPreviewCallback *previewCallback) = 0; diff --git a/plugins/decklink/platform.hpp b/plugins/decklink/platform.hpp index 80b25a7..21820d5 100644 --- a/plugins/decklink/platform.hpp +++ b/plugins/decklink/platform.hpp @@ -7,6 +7,7 @@ typedef BOOL decklink_bool_t; typedef BSTR decklink_string_t; IDeckLinkDiscovery *CreateDeckLinkDiscoveryInstance(void); IDeckLinkIterator *CreateDeckLinkIteratorInstance(void); +IDeckLinkVideoConversion *CreateVideoConversionInstance(void); #define IUnknownUUID IID_IUnknown typedef REFIID CFUUIDBytes; #define CFUUIDGetUUIDBytes(x) x diff --git a/plugins/decklink/win/CMakeLists.txt b/plugins/decklink/win/CMakeLists.txt index fca4e5d..ecb4cc9 100644 --- a/plugins/decklink/win/CMakeLists.txt +++ b/plugins/decklink/win/CMakeLists.txt @@ -7,6 +7,8 @@ endif() include(IDLFileHelper) +include_directories(${CMAKE_SOURCE_DIR}/deps/libcaption) + set(win-decklink-sdk_IDLS decklink-sdk/DeckLinkAPI.idl ) @@ -29,6 +31,7 @@ set(win-decklink_HEADERS ../audio-repack.h ../audio-repack.hpp ../util.hpp + ../OBSVideoFrame.h ) set(MODULE_DESCRIPTION "OBS DeckLink Windows module") @@ -48,7 +51,8 @@ set(win-decklink_SOURCES ../audio-repack.c platform.cpp ../util.cpp - win-decklink.rc) + win-decklink.rc + ../OBSVideoFrame.cpp) add_idl_files(win-decklink-sdk_GENERATED_FILES ${win-decklink-sdk_IDLS} @@ -56,6 +60,7 @@ add_idl_files(win-decklink-sdk_GENERATED_FILES include_directories( ${CMAKE_CURRENT_BINARY_DIR} + "${CMAKE_SOURCE_DIR}/UI/obs-frontend-api" ) add_library(win-decklink MODULE @@ -66,7 +71,9 @@ add_library(win-decklink MODULE ) target_link_libraries(win-decklink - libobs) -set_target_properties(win-decklink PROPERTIES FOLDER "plugins") + libobs + obs-frontend-api + caption) +set_target_properties(win-decklink PROPERTIES FOLDER "plugins/decklink") install_obs_plugin_with_data(win-decklink ../data) diff --git a/plugins/decklink/win/decklink-sdk/DeckLinkAPI.idl b/plugins/decklink/win/decklink-sdk/DeckLinkAPI.idl index 07ee9fe..726dd8b 100644 --- a/plugins/decklink/win/decklink-sdk/DeckLinkAPI.idl +++ b/plugins/decklink/win/decklink-sdk/DeckLinkAPI.idl @@ -1,5 +1,5 @@ /* -LICENSE-START- -** Copyright (c) 2018 Blackmagic Design +** Copyright (c) 2020 Blackmagic Design ** ** Permission is hereby granted, free of charge, to any person or organization ** obtaining a copy of the software and accompanying documentation covered by @@ -7,14 +7,14 @@ ** execute, and transmit the Software, and to prepare derivative works of the ** Software, and to permit third-parties to whom the Software is furnished to ** do so, all subject to the following: -** +** ** The copyright notices in the Software and this entire statement, including ** the above license grant, this restriction and the following disclaimer, ** must be included in all copies of the Software, in whole or in part, and ** all derivative works of the Software, unless such copies or derivative ** works are solely in the form of machine-executable object code generated by ** a source language processor. -** +** ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT @@ -74,28 +74,40 @@ cpp_quote("#endif") /* Enum BMDVideoOutputFlags - Flags to control the output of ancillary data along with video. */ -typedef [v1_enum] enum _BMDVideoOutputFlags { +typedef [v1_enum] enum _BMDVideoOutputFlags { bmdVideoOutputFlagDefault = 0, bmdVideoOutputVANC = 1 << 0, bmdVideoOutputVITC = 1 << 1, bmdVideoOutputRP188 = 1 << 2, - bmdVideoOutputDualStream3D = 1 << 4 + bmdVideoOutputDualStream3D = 1 << 4, + bmdVideoOutputSynchronizeToPlaybackGroup = 1 << 6 } BMDVideoOutputFlags; +/* Enum BMDSupportedVideoModeFlags - Flags to describe supported video modes */ + +typedef [v1_enum] enum _BMDSupportedVideoModeFlags { + bmdSupportedVideoModeDefault = 0, + bmdSupportedVideoModeKeying = 1 << 0, + bmdSupportedVideoModeDualStream3D = 1 << 1, + bmdSupportedVideoModeSDISingleLink = 1 << 2, + bmdSupportedVideoModeSDIDualLink = 1 << 3, + bmdSupportedVideoModeSDIQuadLink = 1 << 4, + bmdSupportedVideoModeInAnyProfile = 1 << 5 +} BMDSupportedVideoModeFlags; + /* Enum BMDPacketType - Type of packet */ -typedef [v1_enum] enum _BMDPacketType { +typedef [v1_enum] enum _BMDPacketType { bmdPacketTypeStreamInterruptedMarker = /* 'sint' */ 0x73696E74, // A packet of this type marks the time when a video stream was interrupted, for example by a disconnected cable bmdPacketTypeStreamData = /* 'sdat' */ 0x73646174 // Regular stream data } BMDPacketType; /* Enum BMDFrameFlags - Frame flags */ -[v1_enum] enum _BMDFrameFlags { +[v1_enum] enum _BMDFrameFlags { bmdFrameFlagDefault = 0, bmdFrameFlagFlipVertical = 1 << 0, bmdFrameContainsHDRMetadata = 1 << 1, - bmdFrameContainsCintelMetadata = 1 << 2, /* Flags that are applicable only to instances of IDeckLinkVideoInputFrame */ @@ -105,15 +117,16 @@ typedef [v1_enum] enum _BMDPacketType { /* Enum BMDVideoInputFlags - Flags applicable to video input */ -[v1_enum] enum _BMDVideoInputFlags { +[v1_enum] enum _BMDVideoInputFlags { bmdVideoInputFlagDefault = 0, bmdVideoInputEnableFormatDetection = 1 << 0, - bmdVideoInputDualStream3D = 1 << 1 + bmdVideoInputDualStream3D = 1 << 1, + bmdVideoInputSynchronizeToCaptureGroup = 1 << 2 }; /* Enum BMDVideoInputFormatChangedEvents - Bitmask passed to the VideoInputFormatChanged notification to identify the properties of the input signal that have changed */ -[v1_enum] enum _BMDVideoInputFormatChangedEvents { +[v1_enum] enum _BMDVideoInputFormatChangedEvents { bmdVideoInputDisplayModeChanged = 1 << 0, bmdVideoInputFieldDominanceChanged = 1 << 1, bmdVideoInputColorspaceChanged = 1 << 2 @@ -121,15 +134,18 @@ typedef [v1_enum] enum _BMDPacketType { /* Enum BMDDetectedVideoInputFormatFlags - Flags passed to the VideoInputFormatChanged notification to describe the detected video input signal */ -[v1_enum] enum _BMDDetectedVideoInputFormatFlags { +[v1_enum] enum _BMDDetectedVideoInputFormatFlags { bmdDetectedVideoInputYCbCr422 = 1 << 0, bmdDetectedVideoInputRGB444 = 1 << 1, - bmdDetectedVideoInputDualStream3D = 1 << 2 + bmdDetectedVideoInputDualStream3D = 1 << 2, + bmdDetectedVideoInput12BitDepth = 1 << 3, + bmdDetectedVideoInput10BitDepth = 1 << 4, + bmdDetectedVideoInput8BitDepth = 1 << 5 }; /* Enum BMDDeckLinkCapturePassthroughMode - Enumerates whether the video output is electrically connected to the video input or if the clean switching mode is enabled */ -[v1_enum] enum _BMDDeckLinkCapturePassthroughMode { +[v1_enum] enum _BMDDeckLinkCapturePassthroughMode { bmdDeckLinkCapturePassthroughModeDisabled = /* 'pdis' */ 0x70646973, bmdDeckLinkCapturePassthroughModeDirect = /* 'pdir' */ 0x70646972, bmdDeckLinkCapturePassthroughModeCleanSwitch = /* 'pcln' */ 0x70636C6E @@ -137,58 +153,50 @@ typedef [v1_enum] enum _BMDPacketType { /* Enum BMDOutputFrameCompletionResult - Frame Completion Callback */ -typedef [v1_enum] enum _BMDOutputFrameCompletionResult { - bmdOutputFrameCompleted, - bmdOutputFrameDisplayedLate, - bmdOutputFrameDropped, - bmdOutputFrameFlushed +typedef [v1_enum] enum _BMDOutputFrameCompletionResult { + bmdOutputFrameCompleted, + bmdOutputFrameDisplayedLate, + bmdOutputFrameDropped, + bmdOutputFrameFlushed } BMDOutputFrameCompletionResult; /* Enum BMDReferenceStatus - GenLock input status */ -typedef [v1_enum] enum _BMDReferenceStatus { +typedef [v1_enum] enum _BMDReferenceStatus { bmdReferenceNotSupportedByHardware = 1 << 0, bmdReferenceLocked = 1 << 1 } BMDReferenceStatus; /* Enum BMDAudioFormat - Audio Format */ -typedef [v1_enum] enum _BMDAudioFormat { +typedef [v1_enum] enum _BMDAudioFormat { bmdAudioFormatPCM = /* 'lpcm' */ 0x6C70636D // Linear signed PCM samples } BMDAudioFormat; /* Enum BMDAudioSampleRate - Audio sample rates supported for output/input */ -typedef [v1_enum] enum _BMDAudioSampleRate { +typedef [v1_enum] enum _BMDAudioSampleRate { bmdAudioSampleRate48kHz = 48000 } BMDAudioSampleRate; /* Enum BMDAudioSampleType - Audio sample sizes supported for output/input */ -typedef [v1_enum] enum _BMDAudioSampleType { +typedef [v1_enum] enum _BMDAudioSampleType { bmdAudioSampleType16bitInteger = 16, bmdAudioSampleType32bitInteger = 32 } BMDAudioSampleType; /* Enum BMDAudioOutputStreamType - Audio output stream type */ -typedef [v1_enum] enum _BMDAudioOutputStreamType { - bmdAudioOutputStreamContinuous, - bmdAudioOutputStreamContinuousDontResample, - bmdAudioOutputStreamTimestamped +typedef [v1_enum] enum _BMDAudioOutputStreamType { + bmdAudioOutputStreamContinuous, + bmdAudioOutputStreamContinuousDontResample, + bmdAudioOutputStreamTimestamped } BMDAudioOutputStreamType; -/* Enum BMDDisplayModeSupport - Output mode supported flags */ - -typedef [v1_enum] enum _BMDDisplayModeSupport { - bmdDisplayModeNotSupported = 0, - bmdDisplayModeSupported, - bmdDisplayModeSupportedWithConversion -} BMDDisplayModeSupport; - /* Enum BMDAncillaryPacketFormat - Ancillary packet format */ -typedef [v1_enum] enum _BMDAncillaryPacketFormat { +typedef [v1_enum] enum _BMDAncillaryPacketFormat { bmdAncillaryPacketFormatUInt8 = /* 'ui08' */ 0x75693038, bmdAncillaryPacketFormatUInt16 = /* 'ui16' */ 0x75693136, bmdAncillaryPacketFormatYCbCr10 = /* 'v210' */ 0x76323130 @@ -196,11 +204,12 @@ typedef [v1_enum] enum _BMDAncillaryPacketFormat { /* Enum BMDTimecodeFormat - Timecode formats for frame metadata */ -typedef [v1_enum] enum _BMDTimecodeFormat { +typedef [v1_enum] enum _BMDTimecodeFormat { bmdTimecodeRP188VITC1 = /* 'rpv1' */ 0x72707631, // RP188 timecode where DBB1 equals VITC1 (line 9) bmdTimecodeRP188VITC2 = /* 'rp12' */ 0x72703132, // RP188 timecode where DBB1 equals VITC2 (line 9 for progressive or line 571 for interlaced/PsF) bmdTimecodeRP188LTC = /* 'rplt' */ 0x72706C74, // RP188 timecode where DBB1 equals LTC (line 10) - bmdTimecodeRP188Any = /* 'rp18' */ 0x72703138, // For capture: return the first valid timecode in {VITC1, LTC ,VITC2} - For playback: set the timecode as VITC1 + bmdTimecodeRP188HighFrameRate = /* 'rphr' */ 0x72706872, // RP188 timecode where DBB1 is an HFRTC (SMPTE ST 12-3), the only timecode allowing the frame value to go above 30 + bmdTimecodeRP188Any = /* 'rp18' */ 0x72703138, // Convenience for capture, returning the first valid timecode in {HFRTC (if supported), VITC1, LTC, VITC2} bmdTimecodeVITC = /* 'vitc' */ 0x76697463, bmdTimecodeVITCField2 = /* 'vit2' */ 0x76697432, bmdTimecodeSerial = /* 'seri' */ 0x73657269 @@ -208,21 +217,21 @@ typedef [v1_enum] enum _BMDTimecodeFormat { /* Enum BMDAnalogVideoFlags - Analog video display flags */ -[v1_enum] enum _BMDAnalogVideoFlags { +[v1_enum] enum _BMDAnalogVideoFlags { bmdAnalogVideoFlagCompositeSetup75 = 1 << 0, bmdAnalogVideoFlagComponentBetacamLevels = 1 << 1 }; /* Enum BMDAudioOutputAnalogAESSwitch - Audio output Analog/AESEBU switch */ -typedef [v1_enum] enum _BMDAudioOutputAnalogAESSwitch { +typedef [v1_enum] enum _BMDAudioOutputAnalogAESSwitch { bmdAudioOutputSwitchAESEBU = /* 'aes ' */ 0x61657320, bmdAudioOutputSwitchAnalog = /* 'anlg' */ 0x616E6C67 } BMDAudioOutputAnalogAESSwitch; /* Enum BMDVideoOutputConversionMode - Video/audio conversion mode */ -typedef [v1_enum] enum _BMDVideoOutputConversionMode { +typedef [v1_enum] enum _BMDVideoOutputConversionMode { bmdNoVideoOutputConversion = /* 'none' */ 0x6E6F6E65, bmdVideoOutputLetterboxDownconversion = /* 'ltbx' */ 0x6C746278, bmdVideoOutputAnamorphicDownconversion = /* 'amph' */ 0x616D7068, @@ -241,7 +250,7 @@ typedef [v1_enum] enum _BMDVideoOutputConversionMode { /* Enum BMDVideoInputConversionMode - Video input conversion mode */ -typedef [v1_enum] enum _BMDVideoInputConversionMode { +typedef [v1_enum] enum _BMDVideoInputConversionMode { bmdNoVideoInputConversion = /* 'none' */ 0x6E6F6E65, bmdVideoInputLetterboxDownconversionFromHD1080 = /* '10lb' */ 0x31306C62, bmdVideoInputAnamorphicDownconversionFromHD1080 = /* '10am' */ 0x3130616D, @@ -253,7 +262,7 @@ typedef [v1_enum] enum _BMDVideoInputConversionMode { /* Enum BMDVideo3DPackingFormat - Video 3D packing format */ -typedef [v1_enum] enum _BMDVideo3DPackingFormat { +typedef [v1_enum] enum _BMDVideo3DPackingFormat { bmdVideo3DPackingSidebySideHalf = /* 'sbsh' */ 0x73627368, bmdVideo3DPackingLinebyLine = /* 'lbyl' */ 0x6C62796C, bmdVideo3DPackingTopAndBottom = /* 'tabo' */ 0x7461626F, @@ -264,21 +273,21 @@ typedef [v1_enum] enum _BMDVideo3DPackingFormat { /* Enum BMDIdleVideoOutputOperation - Video output operation when not playing video */ -typedef [v1_enum] enum _BMDIdleVideoOutputOperation { +typedef [v1_enum] enum _BMDIdleVideoOutputOperation { bmdIdleVideoOutputBlack = /* 'blac' */ 0x626C6163, bmdIdleVideoOutputLastFrame = /* 'lafa' */ 0x6C616661 } BMDIdleVideoOutputOperation; /* Enum BMDVideoEncoderFrameCodingMode - Video frame coding mode */ -typedef [v1_enum] enum _BMDVideoEncoderFrameCodingMode { +typedef [v1_enum] enum _BMDVideoEncoderFrameCodingMode { bmdVideoEncoderFrameCodingModeInter = /* 'inte' */ 0x696E7465, bmdVideoEncoderFrameCodingModeIntra = /* 'intr' */ 0x696E7472 } BMDVideoEncoderFrameCodingMode; /* Enum BMDDNxHRLevel - DNxHR Levels */ -typedef [v1_enum] enum _BMDDNxHRLevel { +typedef [v1_enum] enum _BMDDNxHRLevel { bmdDNxHRLevelSQ = /* 'dnsq' */ 0x646E7371, bmdDNxHRLevelLB = /* 'dnlb' */ 0x646E6C62, bmdDNxHRLevelHQ = /* 'dnhq' */ 0x646E6871, @@ -288,7 +297,7 @@ typedef [v1_enum] enum _BMDDNxHRLevel { /* Enum BMDLinkConfiguration - Video link configuration */ -typedef [v1_enum] enum _BMDLinkConfiguration { +typedef [v1_enum] enum _BMDLinkConfiguration { bmdLinkConfigurationSingleLink = /* 'lcsl' */ 0x6C63736C, bmdLinkConfigurationDualLink = /* 'lcdl' */ 0x6C63646C, bmdLinkConfigurationQuadLink = /* 'lcql' */ 0x6C63716C @@ -296,7 +305,7 @@ typedef [v1_enum] enum _BMDLinkConfiguration { /* Enum BMDDeviceInterface - Device interface type */ -typedef [v1_enum] enum _BMDDeviceInterface { +typedef [v1_enum] enum _BMDDeviceInterface { bmdDeviceInterfacePCI = /* 'pci ' */ 0x70636920, bmdDeviceInterfaceUSB = /* 'usb ' */ 0x75736220, bmdDeviceInterfaceThunderbolt = /* 'thun' */ 0x7468756E @@ -304,7 +313,7 @@ typedef [v1_enum] enum _BMDDeviceInterface { /* Enum BMDColorspace - Colorspace */ -typedef [v1_enum] enum _BMDColorspace { +typedef [v1_enum] enum _BMDColorspace { bmdColorspaceRec601 = /* 'r601' */ 0x72363031, bmdColorspaceRec709 = /* 'r709' */ 0x72373039, bmdColorspaceRec2020 = /* '2020' */ 0x32303230 @@ -312,54 +321,35 @@ typedef [v1_enum] enum _BMDColorspace { /* Enum BMDDynamicRange - SDR or HDR */ -typedef [v1_enum] enum _BMDDynamicRange { - bmdDynamicRangeSDR = 0, - bmdDynamicRangeHDRStaticPQ = 1 << 29, // SMPTE ST 2084 - bmdDynamicRangeHDRStaticHLG = 1 << 30 // ITU-R BT.2100-0 +typedef [v1_enum] enum _BMDDynamicRange { + bmdDynamicRangeSDR = 0, // Standard Dynamic Range in accordance with SMPTE ST 2036-1 + bmdDynamicRangeHDRStaticPQ = 1 << 29, // High Dynamic Range PQ in accordance with SMPTE ST 2084 + bmdDynamicRangeHDRStaticHLG = 1 << 30 // High Dynamic Range HLG in accordance with ITU-R BT.2100-0 } BMDDynamicRange; /* Enum BMDDeckLinkHDMIInputEDIDID - DeckLink HDMI Input EDID ID */ -typedef [v1_enum] enum _BMDDeckLinkHDMIInputEDIDID { +typedef [v1_enum] enum _BMDDeckLinkHDMIInputEDIDID { + + /* Integers */ + bmdDeckLinkHDMIInputEDIDDynamicRange = /* 'HIDy' */ 0x48494479 // Parameter is of type BMDDynamicRange. Default is (bmdDynamicRangeSDR|bmdDynamicRangeHDRStaticPQ) } BMDDeckLinkHDMIInputEDIDID; /* Enum BMDDeckLinkFrameMetadataID - DeckLink Frame Metadata ID */ -typedef [v1_enum] enum _BMDDeckLinkFrameMetadataID { +typedef [v1_enum] enum _BMDDeckLinkFrameMetadataID { + + /* Colorspace Metadata - Integers */ + bmdDeckLinkFrameMetadataColorspace = /* 'cspc' */ 0x63737063, // Colorspace of video frame (see BMDColorspace) + + /* HDR Metadata - Integers */ + bmdDeckLinkFrameMetadataHDRElectroOpticalTransferFunc = /* 'eotf' */ 0x656F7466, // EOTF in range 0-7 as per CEA 861.3 - bmdDeckLinkFrameMetadataCintelFilmType = /* 'cfty' */ 0x63667479, // Current film type - bmdDeckLinkFrameMetadataCintelFilmGauge = /* 'cfga' */ 0x63666761, // Current film gauge - bmdDeckLinkFrameMetadataCintelOffsetDetectedHorizontal = /* 'odfh' */ 0x6F646668, // Horizontal offset (pixels) detected in image - bmdDeckLinkFrameMetadataCintelOffsetDetectedVertical = /* 'odfv' */ 0x6F646676, // Vertical offset (pixels) detected in image - bmdDeckLinkFrameMetadataCintelKeykodeLow = /* 'ckkl' */ 0x636B6B6C, // Raw keykode value - low 64 bits - bmdDeckLinkFrameMetadataCintelKeykodeHigh = /* 'ckkh' */ 0x636B6B68, // Raw keykode value - high 64 bits - bmdDeckLinkFrameMetadataCintelTile1Size = /* 'ct1s' */ 0x63743173, // Size in bytes of compressed raw tile 1 - bmdDeckLinkFrameMetadataCintelTile2Size = /* 'ct2s' */ 0x63743273, // Size in bytes of compressed raw tile 2 - bmdDeckLinkFrameMetadataCintelTile3Size = /* 'ct3s' */ 0x63743373, // Size in bytes of compressed raw tile 3 - bmdDeckLinkFrameMetadataCintelTile4Size = /* 'ct4s' */ 0x63743473, // Size in bytes of compressed raw tile 4 - bmdDeckLinkFrameMetadataCintelImageWidth = /* 'IWPx' */ 0x49575078, // Width in pixels of image - bmdDeckLinkFrameMetadataCintelImageHeight = /* 'IHPx' */ 0x49485078, // Height in pixels of image - bmdDeckLinkFrameMetadataCintelLinearMaskingRedInRed = /* 'mrir' */ 0x6D726972, // Red in red linear masking parameter - bmdDeckLinkFrameMetadataCintelLinearMaskingGreenInRed = /* 'mgir' */ 0x6D676972, // Green in red linear masking parameter - bmdDeckLinkFrameMetadataCintelLinearMaskingBlueInRed = /* 'mbir' */ 0x6D626972, // Blue in red linear masking parameter - bmdDeckLinkFrameMetadataCintelLinearMaskingRedInGreen = /* 'mrig' */ 0x6D726967, // Red in green linear masking parameter - bmdDeckLinkFrameMetadataCintelLinearMaskingGreenInGreen = /* 'mgig' */ 0x6D676967, // Green in green linear masking parameter - bmdDeckLinkFrameMetadataCintelLinearMaskingBlueInGreen = /* 'mbig' */ 0x6D626967, // Blue in green linear masking parameter - bmdDeckLinkFrameMetadataCintelLinearMaskingRedInBlue = /* 'mrib' */ 0x6D726962, // Red in blue linear masking parameter - bmdDeckLinkFrameMetadataCintelLinearMaskingGreenInBlue = /* 'mgib' */ 0x6D676962, // Green in blue linear masking parameter - bmdDeckLinkFrameMetadataCintelLinearMaskingBlueInBlue = /* 'mbib' */ 0x6D626962, // Blue in blue linear masking parameter - bmdDeckLinkFrameMetadataCintelLogMaskingRedInRed = /* 'mlrr' */ 0x6D6C7272, // Red in red log masking parameter - bmdDeckLinkFrameMetadataCintelLogMaskingGreenInRed = /* 'mlgr' */ 0x6D6C6772, // Green in red log masking parameter - bmdDeckLinkFrameMetadataCintelLogMaskingBlueInRed = /* 'mlbr' */ 0x6D6C6272, // Blue in red log masking parameter - bmdDeckLinkFrameMetadataCintelLogMaskingRedInGreen = /* 'mlrg' */ 0x6D6C7267, // Red in green log masking parameter - bmdDeckLinkFrameMetadataCintelLogMaskingGreenInGreen = /* 'mlgg' */ 0x6D6C6767, // Green in green log masking parameter - bmdDeckLinkFrameMetadataCintelLogMaskingBlueInGreen = /* 'mlbg' */ 0x6D6C6267, // Blue in green log masking parameter - bmdDeckLinkFrameMetadataCintelLogMaskingRedInBlue = /* 'mlrb' */ 0x6D6C7262, // Red in blue log masking parameter - bmdDeckLinkFrameMetadataCintelLogMaskingGreenInBlue = /* 'mlgb' */ 0x6D6C6762, // Green in blue log masking parameter - bmdDeckLinkFrameMetadataCintelLogMaskingBlueInBlue = /* 'mlbb' */ 0x6D6C6262, // Blue in blue log masking parameter - bmdDeckLinkFrameMetadataCintelFilmFrameRate = /* 'cffr' */ 0x63666672, // Film frame rate + + /* HDR Metadata - Floats */ + bmdDeckLinkFrameMetadataHDRDisplayPrimariesRedX = /* 'hdrx' */ 0x68647278, // Red display primaries in range 0.0 - 1.0 bmdDeckLinkFrameMetadataHDRDisplayPrimariesRedY = /* 'hdry' */ 0x68647279, // Red display primaries in range 0.0 - 1.0 bmdDeckLinkFrameMetadataHDRDisplayPrimariesGreenX = /* 'hdgx' */ 0x68646778, // Green display primaries in range 0.0 - 1.0 @@ -371,33 +361,42 @@ typedef [v1_enum] enum _BMDDeckLinkFrameMetadataID { bmdDeckLinkFrameMetadataHDRMaxDisplayMasteringLuminance = /* 'hdml' */ 0x68646D6C, // Max display mastering luminance in range 1 cd/m2 - 65535 cd/m2 bmdDeckLinkFrameMetadataHDRMinDisplayMasteringLuminance = /* 'hmil' */ 0x686D696C, // Min display mastering luminance in range 0.0001 cd/m2 - 6.5535 cd/m2 bmdDeckLinkFrameMetadataHDRMaximumContentLightLevel = /* 'mcll' */ 0x6D636C6C, // Maximum Content Light Level in range 1 cd/m2 - 65535 cd/m2 - bmdDeckLinkFrameMetadataHDRMaximumFrameAverageLightLevel = /* 'fall' */ 0x66616C6C, // Maximum Frame Average Light Level in range 1 cd/m2 - 65535 cd/m2 - bmdDeckLinkFrameMetadataCintelOffsetToApplyHorizontal = /* 'otah' */ 0x6F746168, // Horizontal offset (pixels) to be applied to image - bmdDeckLinkFrameMetadataCintelOffsetToApplyVertical = /* 'otav' */ 0x6F746176, // Vertical offset (pixels) to be applied to image - bmdDeckLinkFrameMetadataCintelGainRed = /* 'LfRd' */ 0x4C665264, // Red gain parameter to apply after log - bmdDeckLinkFrameMetadataCintelGainGreen = /* 'LfGr' */ 0x4C664772, // Green gain parameter to apply after log - bmdDeckLinkFrameMetadataCintelGainBlue = /* 'LfBl' */ 0x4C66426C, // Blue gain parameter to apply after log - bmdDeckLinkFrameMetadataCintelLiftRed = /* 'GnRd' */ 0x476E5264, // Red lift parameter to apply after log and gain - bmdDeckLinkFrameMetadataCintelLiftGreen = /* 'GnGr' */ 0x476E4772, // Green lift parameter to apply after log and gain - bmdDeckLinkFrameMetadataCintelLiftBlue = /* 'GnBl' */ 0x476E426C // Blue lift parameter to apply after log and gain + bmdDeckLinkFrameMetadataHDRMaximumFrameAverageLightLevel = /* 'fall' */ 0x66616C6C // Maximum Frame Average Light Level in range 1 cd/m2 - 65535 cd/m2 } BMDDeckLinkFrameMetadataID; -/* Enum BMDDuplexMode - Duplex for configurable ports */ +/* Enum BMDProfileID - Identifies a profile */ -typedef [v1_enum] enum _BMDDuplexMode { - bmdDuplexModeFull = /* 'fdup' */ 0x66647570, - bmdDuplexModeHalf = /* 'hdup' */ 0x68647570 -} BMDDuplexMode; +typedef [v1_enum] enum _BMDProfileID { + bmdProfileOneSubDeviceFullDuplex = /* '1dfd' */ 0x31646664, + bmdProfileOneSubDeviceHalfDuplex = /* '1dhd' */ 0x31646864, + bmdProfileTwoSubDevicesFullDuplex = /* '2dfd' */ 0x32646664, + bmdProfileTwoSubDevicesHalfDuplex = /* '2dhd' */ 0x32646864, + bmdProfileFourSubDevicesHalfDuplex = /* '4dhd' */ 0x34646864 +} BMDProfileID; + +/* Enum BMDHDMITimecodePacking - Packing form of timecode on HDMI */ + +typedef [v1_enum] enum _BMDHDMITimecodePacking { + bmdHDMITimecodePackingIEEEOUI000085 = 0x00008500, + bmdHDMITimecodePackingIEEEOUI080046 = 0x08004601, + bmdHDMITimecodePackingIEEEOUI5CF9F0 = 0x5CF9F003 +} BMDHDMITimecodePacking; + +/* Enum BMDInternalKeyingAncillaryDataSource - Source for VANC and timecode data when performing internal keying */ + +typedef [v1_enum] enum _BMDInternalKeyingAncillaryDataSource { + bmdInternalKeyingUsesAncillaryDataFromInputSignal = /* 'ikai' */ 0x696B6169, + bmdInternalKeyingUsesAncillaryDataFromKeyFrame = /* 'ikak' */ 0x696B616B +} BMDInternalKeyingAncillaryDataSource; /* Enum BMDDeckLinkAttributeID - DeckLink Attribute ID */ -typedef [v1_enum] enum _BMDDeckLinkAttributeID { +typedef [v1_enum] enum _BMDDeckLinkAttributeID { /* Flags */ BMDDeckLinkSupportsInternalKeying = /* 'keyi' */ 0x6B657969, BMDDeckLinkSupportsExternalKeying = /* 'keye' */ 0x6B657965, - BMDDeckLinkSupportsHDKeying = /* 'keyh' */ 0x6B657968, BMDDeckLinkSupportsInputFormatDetection = /* 'infd' */ 0x696E6664, BMDDeckLinkHasReferenceInput = /* 'hrin' */ 0x6872696E, BMDDeckLinkHasSerialPort = /* 'hspt' */ 0x68737074, @@ -406,16 +405,20 @@ typedef [v1_enum] enum _BMDDeckLinkAttributeID { BMDDeckLinkHasVideoInputAntiAliasingFilter = /* 'aafl' */ 0x6161666C, BMDDeckLinkHasBypass = /* 'byps' */ 0x62797073, BMDDeckLinkSupportsClockTimingAdjustment = /* 'ctad' */ 0x63746164, - BMDDeckLinkSupportsFullDuplex = /* 'fdup' */ 0x66647570, BMDDeckLinkSupportsFullFrameReferenceInputTimingOffset = /* 'frin' */ 0x6672696E, BMDDeckLinkSupportsSMPTELevelAOutput = /* 'lvla' */ 0x6C766C61, + BMDDeckLinkSupportsAutoSwitchingPPsFOnInput = /* 'apsf' */ 0x61707366, BMDDeckLinkSupportsDualLinkSDI = /* 'sdls' */ 0x73646C73, BMDDeckLinkSupportsQuadLinkSDI = /* 'sqls' */ 0x73716C73, BMDDeckLinkSupportsIdleOutput = /* 'idou' */ 0x69646F75, + BMDDeckLinkVANCRequires10BitYUVVideoFrames = /* 'vioY' */ 0x76696F59, // Legacy product requires v210 active picture for IDeckLinkVideoFrameAncillaryPackets or 10-bit VANC BMDDeckLinkHasLTCTimecodeInput = /* 'hltc' */ 0x686C7463, - BMDDeckLinkSupportsDuplexModeConfiguration = /* 'dupx' */ 0x64757078, BMDDeckLinkSupportsHDRMetadata = /* 'hdrm' */ 0x6864726D, BMDDeckLinkSupportsColorspaceMetadata = /* 'cmet' */ 0x636D6574, + BMDDeckLinkSupportsHDMITimecode = /* 'htim' */ 0x6874696D, + BMDDeckLinkSupportsHighFrameRateTimecode = /* 'HFRT' */ 0x48465254, + BMDDeckLinkSupportsSynchronizeToCaptureGroup = /* 'stcg' */ 0x73746367, + BMDDeckLinkSupportsSynchronizeToPlaybackGroup = /* 'stpg' */ 0x73747067, /* Integers */ @@ -438,7 +441,10 @@ typedef [v1_enum] enum _BMDDeckLinkAttributeID { BMDDeckLinkAudioInputXLRChannelCount = /* 'aixc' */ 0x61697863, BMDDeckLinkAudioOutputRCAChannelCount = /* 'aorc' */ 0x616F7263, BMDDeckLinkAudioOutputXLRChannelCount = /* 'aoxc' */ 0x616F7863, - BMDDeckLinkPairedDevicePersistentID = /* 'ppid' */ 0x70706964, + BMDDeckLinkProfileID = /* 'prid' */ 0x70726964, // Returns a BMDProfileID + BMDDeckLinkDuplex = /* 'dupx' */ 0x64757078, + BMDDeckLinkMinimumPrerollFrames = /* 'mprf' */ 0x6D707266, + BMDDeckLinkSupportedDynamicRange = /* 'sudr' */ 0x73756472, /* Floats */ @@ -460,18 +466,25 @@ typedef [v1_enum] enum _BMDDeckLinkAttributeID { /* Enum BMDDeckLinkAPIInformationID - DeckLinkAPI information ID */ -typedef [v1_enum] enum _BMDDeckLinkAPIInformationID { +typedef [v1_enum] enum _BMDDeckLinkAPIInformationID { + + /* Integer or String */ + BMDDeckLinkAPIVersion = /* 'vers' */ 0x76657273 } BMDDeckLinkAPIInformationID; /* Enum BMDDeckLinkStatusID - DeckLink Status ID */ -typedef [v1_enum] enum _BMDDeckLinkStatusID { +typedef [v1_enum] enum _BMDDeckLinkStatusID { /* Integers */ bmdDeckLinkStatusDetectedVideoInputMode = /* 'dvim' */ 0x6476696D, - bmdDeckLinkStatusDetectedVideoInputFlags = /* 'dvif' */ 0x64766966, + bmdDeckLinkStatusDetectedVideoInputFormatFlags = /* 'dvff' */ 0x64766666, + bmdDeckLinkStatusDetectedVideoInputFieldDominance = /* 'dvfd' */ 0x64766664, + bmdDeckLinkStatusDetectedVideoInputColorspace = /* 'dscl' */ 0x6473636C, + bmdDeckLinkStatusDetectedVideoInputDynamicRange = /* 'dsdr' */ 0x64736472, + bmdDeckLinkStatusDetectedSDILinkConfiguration = /* 'dslc' */ 0x64736C63, bmdDeckLinkStatusCurrentVideoInputMode = /* 'cvim' */ 0x6376696D, bmdDeckLinkStatusCurrentVideoInputPixelFormat = /* 'cvip' */ 0x63766970, bmdDeckLinkStatusCurrentVideoInputFlags = /* 'cvif' */ 0x63766966, @@ -482,7 +495,6 @@ typedef [v1_enum] enum _BMDDeckLinkStatusID { bmdDeckLinkStatusLastVideoOutputPixelFormat = /* 'opix' */ 0x6F706978, bmdDeckLinkStatusReferenceSignalMode = /* 'refm' */ 0x7265666D, bmdDeckLinkStatusReferenceSignalFlags = /* 'reff' */ 0x72656666, - bmdDeckLinkStatusDuplexMode = /* 'dupx' */ 0x64757078, bmdDeckLinkStatusBusy = /* 'busy' */ 0x62757379, bmdDeckLinkStatusInterchangeablePanelType = /* 'icpt' */ 0x69637074, bmdDeckLinkStatusDeviceTemperature = /* 'dtmp' */ 0x64746D70, @@ -491,35 +503,38 @@ typedef [v1_enum] enum _BMDDeckLinkStatusID { bmdDeckLinkStatusVideoInputSignalLocked = /* 'visl' */ 0x7669736C, bmdDeckLinkStatusReferenceSignalLocked = /* 'refl' */ 0x7265666C, + + /* Bytes */ + bmdDeckLinkStatusReceivedEDID = /* 'edid' */ 0x65646964 } BMDDeckLinkStatusID; /* Enum BMDDeckLinkVideoStatusFlags - */ -typedef [v1_enum] enum _BMDDeckLinkVideoStatusFlags { +typedef [v1_enum] enum _BMDDeckLinkVideoStatusFlags { bmdDeckLinkVideoStatusPsF = 1 << 0, bmdDeckLinkVideoStatusDualStream3D = 1 << 1 } BMDDeckLinkVideoStatusFlags; -/* Enum BMDDuplexStatus - Duplex status of the device */ +/* Enum BMDDuplexMode - Duplex of the device */ -typedef [v1_enum] enum _BMDDuplexStatus { - bmdDuplexStatusFullDuplex = /* 'fdup' */ 0x66647570, - bmdDuplexStatusHalfDuplex = /* 'hdup' */ 0x68647570, - bmdDuplexStatusSimplex = /* 'splx' */ 0x73706C78, - bmdDuplexStatusInactive = /* 'inac' */ 0x696E6163 -} BMDDuplexStatus; +typedef [v1_enum] enum _BMDDuplexMode { + bmdDuplexFull = /* 'dxfu' */ 0x64786675, + bmdDuplexHalf = /* 'dxha' */ 0x64786861, + bmdDuplexSimplex = /* 'dxsp' */ 0x64787370, + bmdDuplexInactive = /* 'dxin' */ 0x6478696E +} BMDDuplexMode; /* Enum BMDPanelType - The type of interchangeable panel */ -typedef [v1_enum] enum _BMDPanelType { +typedef [v1_enum] enum _BMDPanelType { bmdPanelNotDetected = /* 'npnl' */ 0x6E706E6C, bmdPanelTeranexMiniSmartPanel = /* 'tmsm' */ 0x746D736D } BMDPanelType; /* Enum BMDDeviceBusyState - Current device busy state */ -[v1_enum] enum _BMDDeviceBusyState { +[v1_enum] enum _BMDDeviceBusyState { bmdDeviceCaptureBusy = 1 << 0, bmdDevicePlaybackBusy = 1 << 1, bmdDeviceSerialPortBusy = 1 << 2 @@ -527,14 +542,14 @@ typedef [v1_enum] enum _BMDPanelType { /* Enum BMDVideoIOSupport - Device video input/output support */ -typedef [v1_enum] enum _BMDVideoIOSupport { +typedef [v1_enum] enum _BMDVideoIOSupport { bmdDeviceSupportsCapture = 1 << 0, bmdDeviceSupportsPlayback = 1 << 1 } BMDVideoIOSupport; /* Enum BMD3DPreviewFormat - Linked Frame preview format */ -typedef [v1_enum] enum _BMD3DPreviewFormat { +typedef [v1_enum] enum _BMD3DPreviewFormat { bmd3DPreviewFormatDefault = /* 'defa' */ 0x64656661, bmd3DPreviewFormatLeftOnly = /* 'left' */ 0x6C656674, bmd3DPreviewFormatRightOnly = /* 'righ' */ 0x72696768, @@ -544,7 +559,7 @@ typedef [v1_enum] enum _BMD3DPreviewFormat { /* Enum BMDNotifications - Events that can be subscribed through IDeckLinkNotification */ -typedef [v1_enum] enum _BMDNotifications { +typedef [v1_enum] enum _BMDNotifications { bmdPreferencesChanged = /* 'pref' */ 0x70726566, bmdStatusChanged = /* 'stat' */ 0x73746174 } BMDNotifications; @@ -581,7 +596,11 @@ interface IDeckLinkGLScreenPreviewHelper; interface IDeckLinkDX9ScreenPreviewHelper; interface IDeckLinkNotificationCallback; interface IDeckLinkNotification; -interface IDeckLinkAttributes; +interface IDeckLinkProfileAttributes; +interface IDeckLinkProfileIterator; +interface IDeckLinkProfile; +interface IDeckLinkProfileCallback; +interface IDeckLinkProfileManager; interface IDeckLinkStatus; interface IDeckLinkKeyer; interface IDeckLinkVideoConversion; @@ -596,20 +615,20 @@ interface IDeckLinkDiscovery; helpstring("Frame completion callback.") ] interface IDeckLinkVideoOutputCallback : IUnknown { - HRESULT ScheduledFrameCompleted([in] IDeckLinkVideoFrame *completedFrame, [in] BMDOutputFrameCompletionResult result); - HRESULT ScheduledPlaybackHasStopped(void); + HRESULT ScheduledFrameCompleted ([in] IDeckLinkVideoFrame* completedFrame, [in] BMDOutputFrameCompletionResult result); + HRESULT ScheduledPlaybackHasStopped (void); }; /* Interface IDeckLinkInputCallback - Frame arrival callback. */ [ object, - uuid(DD04E5EC-7415-42AB-AE4A-E80C4DFC044A), + uuid(C6FCE4C9-C4E4-4047-82FB-5D238232A902), helpstring("Frame arrival callback.") ] interface IDeckLinkInputCallback : IUnknown { - HRESULT VideoInputFormatChanged([in] BMDVideoInputFormatChangedEvents notificationEvents, [in] IDeckLinkDisplayMode *newDisplayMode, [in] BMDDetectedVideoInputFormatFlags detectedSignalFlags); - HRESULT VideoInputFrameArrived([in] IDeckLinkVideoInputFrame* videoFrame, [in] IDeckLinkAudioInputPacket* audioPacket); + HRESULT VideoInputFormatChanged ([in] BMDVideoInputFormatChangedEvents notificationEvents, [in] IDeckLinkDisplayMode* newDisplayMode, [in] BMDDetectedVideoInputFormatFlags detectedSignalFlags); + HRESULT VideoInputFrameArrived ([in] IDeckLinkVideoInputFrame* videoFrame, [in] IDeckLinkAudioInputPacket* audioPacket); }; /* Interface IDeckLinkEncoderInputCallback - Frame arrival callback. */ @@ -620,9 +639,9 @@ interface IDeckLinkDiscovery; helpstring("Frame arrival callback.") ] interface IDeckLinkEncoderInputCallback : IUnknown { - HRESULT VideoInputSignalChanged([in] BMDVideoInputFormatChangedEvents notificationEvents, [in] IDeckLinkDisplayMode *newDisplayMode, [in] BMDDetectedVideoInputFormatFlags detectedSignalFlags); - HRESULT VideoPacketArrived([in] IDeckLinkEncoderVideoPacket* videoPacket); - HRESULT AudioPacketArrived([in] IDeckLinkEncoderAudioPacket* audioPacket); + HRESULT VideoInputSignalChanged ([in] BMDVideoInputFormatChangedEvents notificationEvents, [in] IDeckLinkDisplayMode* newDisplayMode, [in] BMDDetectedVideoInputFormatFlags detectedSignalFlags); + HRESULT VideoPacketArrived ([in] IDeckLinkEncoderVideoPacket* videoPacket); + HRESULT AudioPacketArrived ([in] IDeckLinkEncoderAudioPacket* audioPacket); }; /* Interface IDeckLinkMemoryAllocator - Memory allocator for video frames. */ @@ -630,15 +649,14 @@ interface IDeckLinkDiscovery; [ object, uuid(B36EB6E7-9D29-4AA8-92EF-843B87A289E8), - local, + local, helpstring("Memory allocator for video frames.") ] interface IDeckLinkMemoryAllocator : IUnknown { - HRESULT AllocateBuffer([in] unsigned int bufferSize, [out] void **allocatedBuffer); - HRESULT ReleaseBuffer([in] void *buffer); - - HRESULT Commit(void); - HRESULT Decommit(void); + HRESULT AllocateBuffer ([in] unsigned int bufferSize, [out] void** allocatedBuffer); + HRESULT ReleaseBuffer ([in] void* buffer); + HRESULT Commit (void); + HRESULT Decommit (void); }; /* Interface IDeckLinkAudioOutputCallback - Optional callback to allow audio samples to be pulled as required. */ @@ -646,22 +664,22 @@ interface IDeckLinkDiscovery; [ object, uuid(403C681B-7F46-4A12-B993-2BB127084EE6), - local, + local, helpstring("Optional callback to allow audio samples to be pulled as required.") ] interface IDeckLinkAudioOutputCallback : IUnknown { - HRESULT RenderAudioSamples([in] BOOL preroll); + HRESULT RenderAudioSamples ([in] BOOL preroll); }; -/* Interface IDeckLinkIterator - enumerates installed DeckLink hardware */ +/* Interface IDeckLinkIterator - Enumerates installed DeckLink hardware */ [ object, uuid(50FB36CD-3063-4B73-BDBB-958087F2D8BA), - helpstring("enumerates installed DeckLink hardware") + helpstring("Enumerates installed DeckLink hardware") ] interface IDeckLinkIterator : IUnknown { - HRESULT Next([out] IDeckLink **deckLinkInstance); + HRESULT Next ([out] IDeckLink** deckLinkInstance); }; /* Interface IDeckLinkAPIInformation - DeckLinkAPI attribute interface */ @@ -672,107 +690,101 @@ interface IDeckLinkDiscovery; helpstring("DeckLinkAPI attribute interface") ] interface IDeckLinkAPIInformation : IUnknown { - HRESULT GetFlag([in] BMDDeckLinkAPIInformationID cfgID, [out] BOOL *value); - HRESULT GetInt([in] BMDDeckLinkAPIInformationID cfgID, [out] LONGLONG *value); - HRESULT GetFloat([in] BMDDeckLinkAPIInformationID cfgID, [out] double *value); - HRESULT GetString([in] BMDDeckLinkAPIInformationID cfgID, [out] BSTR *value); + HRESULT GetFlag ([in] BMDDeckLinkAPIInformationID cfgID, [out] BOOL* value); + HRESULT GetInt ([in] BMDDeckLinkAPIInformationID cfgID, [out] LONGLONG* value); + HRESULT GetFloat ([in] BMDDeckLinkAPIInformationID cfgID, [out] double* value); + HRESULT GetString ([in] BMDDeckLinkAPIInformationID cfgID, [out] BSTR* value); }; /* Interface IDeckLinkOutput - Created by QueryInterface from IDeckLink. */ [ object, - uuid(CC5C8A6E-3F2F-4B3A-87EA-FD78AF300564), - local, + uuid(BE2D9020-461E-442F-84B7-E949CB953B9D), + local, helpstring("Created by QueryInterface from IDeckLink.") ] interface IDeckLinkOutput : IUnknown { - HRESULT DoesSupportVideoMode([in] BMDDisplayMode displayMode, [in] BMDPixelFormat pixelFormat, [in] BMDVideoOutputFlags flags, [out] BMDDisplayModeSupport *result, [out] IDeckLinkDisplayMode **resultDisplayMode); - HRESULT GetDisplayModeIterator([out] IDeckLinkDisplayModeIterator **iterator); - - HRESULT SetScreenPreviewCallback([in] IDeckLinkScreenPreviewCallback *previewCallback); + HRESULT DoesSupportVideoMode ([in] BMDVideoConnection connection /* If a value of bmdVideoConnectionUnspecified is specified, the caller does not care about the connection */, [in] BMDDisplayMode requestedMode, [in] BMDPixelFormat requestedPixelFormat, [in] BMDVideoOutputConversionMode conversionMode, [in] BMDSupportedVideoModeFlags flags, [out] BMDDisplayMode* actualMode, [out] BOOL* supported); + HRESULT GetDisplayMode ([in] BMDDisplayMode displayMode, [out] IDeckLinkDisplayMode** resultDisplayMode); + HRESULT GetDisplayModeIterator ([out] IDeckLinkDisplayModeIterator** iterator); + HRESULT SetScreenPreviewCallback ([in] IDeckLinkScreenPreviewCallback* previewCallback); /* Video Output */ - HRESULT EnableVideoOutput([in] BMDDisplayMode displayMode, [in] BMDVideoOutputFlags flags); - HRESULT DisableVideoOutput(void); - - HRESULT SetVideoOutputFrameMemoryAllocator([in] IDeckLinkMemoryAllocator *theAllocator); - HRESULT CreateVideoFrame([in] int width, [in] int height, [in] int rowBytes, [in] BMDPixelFormat pixelFormat, [in] BMDFrameFlags flags, [out] IDeckLinkMutableVideoFrame **outFrame); - HRESULT CreateAncillaryData([in] BMDPixelFormat pixelFormat, [out] IDeckLinkVideoFrameAncillary **outBuffer); // Use of IDeckLinkVideoFrameAncillaryPackets is preferred - - HRESULT DisplayVideoFrameSync([in] IDeckLinkVideoFrame *theFrame); - HRESULT ScheduleVideoFrame([in] IDeckLinkVideoFrame *theFrame, [in] BMDTimeValue displayTime, [in] BMDTimeValue displayDuration, [in] BMDTimeScale timeScale); - HRESULT SetScheduledFrameCompletionCallback([in] IDeckLinkVideoOutputCallback *theCallback); - HRESULT GetBufferedVideoFrameCount([out] unsigned int *bufferedFrameCount); + HRESULT EnableVideoOutput ([in] BMDDisplayMode displayMode, [in] BMDVideoOutputFlags flags); + HRESULT DisableVideoOutput (void); + HRESULT SetVideoOutputFrameMemoryAllocator ([in] IDeckLinkMemoryAllocator* theAllocator); + HRESULT CreateVideoFrame ([in] int width, [in] int height, [in] int rowBytes, [in] BMDPixelFormat pixelFormat, [in] BMDFrameFlags flags, [out] IDeckLinkMutableVideoFrame** outFrame); + HRESULT CreateAncillaryData ([in] BMDPixelFormat pixelFormat, [out] IDeckLinkVideoFrameAncillary** outBuffer); // Use of IDeckLinkVideoFrameAncillaryPackets is preferred + HRESULT DisplayVideoFrameSync ([in] IDeckLinkVideoFrame* theFrame); + HRESULT ScheduleVideoFrame ([in] IDeckLinkVideoFrame* theFrame, [in] BMDTimeValue displayTime, [in] BMDTimeValue displayDuration, [in] BMDTimeScale timeScale); + HRESULT SetScheduledFrameCompletionCallback ([in] IDeckLinkVideoOutputCallback* theCallback); + HRESULT GetBufferedVideoFrameCount ([out] unsigned int* bufferedFrameCount); /* Audio Output */ - HRESULT EnableAudioOutput([in] BMDAudioSampleRate sampleRate, [in] BMDAudioSampleType sampleType, [in] unsigned int channelCount, [in] BMDAudioOutputStreamType streamType); - HRESULT DisableAudioOutput(void); - - HRESULT WriteAudioSamplesSync([in] void *buffer, [in] unsigned int sampleFrameCount, [out] unsigned int *sampleFramesWritten); - - HRESULT BeginAudioPreroll(void); - HRESULT EndAudioPreroll(void); - HRESULT ScheduleAudioSamples([in] void *buffer, [in] unsigned int sampleFrameCount, [in] BMDTimeValue streamTime, [in] BMDTimeScale timeScale, [out] unsigned int *sampleFramesWritten); - - HRESULT GetBufferedAudioSampleFrameCount([out] unsigned int *bufferedSampleFrameCount); - HRESULT FlushBufferedAudioSamples(void); - - HRESULT SetAudioCallback([in] IDeckLinkAudioOutputCallback *theCallback); + HRESULT EnableAudioOutput ([in] BMDAudioSampleRate sampleRate, [in] BMDAudioSampleType sampleType, [in] unsigned int channelCount, [in] BMDAudioOutputStreamType streamType); + HRESULT DisableAudioOutput (void); + HRESULT WriteAudioSamplesSync ([in] void* buffer, [in] unsigned int sampleFrameCount, [out] unsigned int* sampleFramesWritten); + HRESULT BeginAudioPreroll (void); + HRESULT EndAudioPreroll (void); + HRESULT ScheduleAudioSamples ([in] void* buffer, [in] unsigned int sampleFrameCount, [in] BMDTimeValue streamTime, [in] BMDTimeScale timeScale, [out] unsigned int* sampleFramesWritten); + HRESULT GetBufferedAudioSampleFrameCount ([out] unsigned int* bufferedSampleFrameCount); + HRESULT FlushBufferedAudioSamples (void); + HRESULT SetAudioCallback ([in] IDeckLinkAudioOutputCallback* theCallback); /* Output Control */ - HRESULT StartScheduledPlayback([in] BMDTimeValue playbackStartTime, [in] BMDTimeScale timeScale, [in] double playbackSpeed); - HRESULT StopScheduledPlayback([in] BMDTimeValue stopPlaybackAtTime, [out] BMDTimeValue *actualStopTime, [in] BMDTimeScale timeScale); - HRESULT IsScheduledPlaybackRunning([out] BOOL *active); - HRESULT GetScheduledStreamTime([in] BMDTimeScale desiredTimeScale, [out] BMDTimeValue *streamTime, [out] double *playbackSpeed); - HRESULT GetReferenceStatus([out] BMDReferenceStatus *referenceStatus); + HRESULT StartScheduledPlayback ([in] BMDTimeValue playbackStartTime, [in] BMDTimeScale timeScale, [in] double playbackSpeed); + HRESULT StopScheduledPlayback ([in] BMDTimeValue stopPlaybackAtTime, [out] BMDTimeValue* actualStopTime, [in] BMDTimeScale timeScale); + HRESULT IsScheduledPlaybackRunning ([out] BOOL* active); + HRESULT GetScheduledStreamTime ([in] BMDTimeScale desiredTimeScale, [out] BMDTimeValue* streamTime, [out] double* playbackSpeed); + HRESULT GetReferenceStatus ([out] BMDReferenceStatus* referenceStatus); /* Hardware Timing */ - HRESULT GetHardwareReferenceClock([in] BMDTimeScale desiredTimeScale, [out] BMDTimeValue *hardwareTime, [out] BMDTimeValue *timeInFrame, [out] BMDTimeValue *ticksPerFrame); - HRESULT GetFrameCompletionReferenceTimestamp([in] IDeckLinkVideoFrame *theFrame, [in] BMDTimeScale desiredTimeScale, [out] BMDTimeValue *frameCompletionTimestamp); + HRESULT GetHardwareReferenceClock ([in] BMDTimeScale desiredTimeScale, [out] BMDTimeValue* hardwareTime, [out] BMDTimeValue* timeInFrame, [out] BMDTimeValue* ticksPerFrame); + HRESULT GetFrameCompletionReferenceTimestamp ([in] IDeckLinkVideoFrame* theFrame, [in] BMDTimeScale desiredTimeScale, [out] BMDTimeValue* frameCompletionTimestamp); }; /* Interface IDeckLinkInput - Created by QueryInterface from IDeckLink. */ [ object, - uuid(AF22762B-DFAC-4846-AA79-FA8883560995), + uuid(C21CDB6E-F414-46E4-A636-80A566E0ED37), helpstring("Created by QueryInterface from IDeckLink.") ] interface IDeckLinkInput : IUnknown { - HRESULT DoesSupportVideoMode([in] BMDDisplayMode displayMode, [in] BMDPixelFormat pixelFormat, [in] BMDVideoInputFlags flags, [out] BMDDisplayModeSupport *result, [out] IDeckLinkDisplayMode **resultDisplayMode); - HRESULT GetDisplayModeIterator([out] IDeckLinkDisplayModeIterator **iterator); - - HRESULT SetScreenPreviewCallback([in] IDeckLinkScreenPreviewCallback *previewCallback); + HRESULT DoesSupportVideoMode ([in] BMDVideoConnection connection /* If a value of bmdVideoConnectionUnspecified is specified, the caller does not care about the connection */, [in] BMDDisplayMode requestedMode, [in] BMDPixelFormat requestedPixelFormat, [in] BMDVideoInputConversionMode conversionMode, [in] BMDSupportedVideoModeFlags flags, [out] BMDDisplayMode* actualMode, [out] BOOL* supported); + HRESULT GetDisplayMode ([in] BMDDisplayMode displayMode, [out] IDeckLinkDisplayMode** resultDisplayMode); + HRESULT GetDisplayModeIterator ([out] IDeckLinkDisplayModeIterator** iterator); + HRESULT SetScreenPreviewCallback ([in] IDeckLinkScreenPreviewCallback* previewCallback); /* Video Input */ - HRESULT EnableVideoInput([in] BMDDisplayMode displayMode, [in] BMDPixelFormat pixelFormat, [in] BMDVideoInputFlags flags); - HRESULT DisableVideoInput(void); - HRESULT GetAvailableVideoFrameCount([out] unsigned int *availableFrameCount); - HRESULT SetVideoInputFrameMemoryAllocator([in] IDeckLinkMemoryAllocator *theAllocator); + HRESULT EnableVideoInput ([in] BMDDisplayMode displayMode, [in] BMDPixelFormat pixelFormat, [in] BMDVideoInputFlags flags); + HRESULT DisableVideoInput (void); + HRESULT GetAvailableVideoFrameCount ([out] unsigned int* availableFrameCount); + HRESULT SetVideoInputFrameMemoryAllocator ([in] IDeckLinkMemoryAllocator* theAllocator); /* Audio Input */ - HRESULT EnableAudioInput([in] BMDAudioSampleRate sampleRate, [in] BMDAudioSampleType sampleType, [in] unsigned int channelCount); - HRESULT DisableAudioInput(void); - HRESULT GetAvailableAudioSampleFrameCount([out] unsigned int *availableSampleFrameCount); + HRESULT EnableAudioInput ([in] BMDAudioSampleRate sampleRate, [in] BMDAudioSampleType sampleType, [in] unsigned int channelCount); + HRESULT DisableAudioInput (void); + HRESULT GetAvailableAudioSampleFrameCount ([out] unsigned int* availableSampleFrameCount); /* Input Control */ - HRESULT StartStreams(void); - HRESULT StopStreams(void); - HRESULT PauseStreams(void); - HRESULT FlushStreams(void); - HRESULT SetCallback([in] IDeckLinkInputCallback *theCallback); + HRESULT StartStreams (void); + HRESULT StopStreams (void); + HRESULT PauseStreams (void); + HRESULT FlushStreams (void); + HRESULT SetCallback ([in] IDeckLinkInputCallback* theCallback); /* Hardware Timing */ - HRESULT GetHardwareReferenceClock([in] BMDTimeScale desiredTimeScale, [out] BMDTimeValue *hardwareTime, [out] BMDTimeValue *timeInFrame, [out] BMDTimeValue *ticksPerFrame); + HRESULT GetHardwareReferenceClock ([in] BMDTimeScale desiredTimeScale, [out] BMDTimeValue* hardwareTime, [out] BMDTimeValue* timeInFrame, [out] BMDTimeValue* ticksPerFrame); }; /* Interface IDeckLinkHDMIInputEDID - Created by QueryInterface from IDeckLink. Releasing all references will restore EDID to default */ @@ -783,46 +795,47 @@ interface IDeckLinkDiscovery; helpstring("Created by QueryInterface from IDeckLink. Releasing all references will restore EDID to default") ] interface IDeckLinkHDMIInputEDID : IUnknown { - HRESULT SetInt([in] BMDDeckLinkHDMIInputEDIDID cfgID, [in] LONGLONG value); - HRESULT GetInt([in] BMDDeckLinkHDMIInputEDIDID cfgID, [out] LONGLONG *value); - HRESULT WriteToEDID(void); + HRESULT SetInt ([in] BMDDeckLinkHDMIInputEDIDID cfgID, [in] LONGLONG value); + HRESULT GetInt ([in] BMDDeckLinkHDMIInputEDIDID cfgID, [out] LONGLONG* value); + HRESULT WriteToEDID (void); }; /* Interface IDeckLinkEncoderInput - Created by QueryInterface from IDeckLink. */ [ object, - uuid(270587DA-6B7D-42E7-A1F0-6D853F581185), + uuid(F222551D-13DF-4FD8-B587-9D4F19EC12C9), helpstring("Created by QueryInterface from IDeckLink.") ] interface IDeckLinkEncoderInput : IUnknown { - HRESULT DoesSupportVideoMode([in] BMDDisplayMode displayMode, [in] BMDPixelFormat pixelFormat, [in] BMDVideoInputFlags flags, [out] BMDDisplayModeSupport *result, [out] IDeckLinkDisplayMode **resultDisplayMode); - HRESULT GetDisplayModeIterator([out] IDeckLinkDisplayModeIterator **iterator); + HRESULT DoesSupportVideoMode ([in] BMDVideoConnection connection /* If a value of bmdVideoConnectionUnspecified is specified, the caller does not care about the connection */, [in] BMDDisplayMode requestedMode, [in] BMDPixelFormat requestedCodec, [in] unsigned int requestedCodecProfile, [in] BMDSupportedVideoModeFlags flags, [out] BOOL* supported); + HRESULT GetDisplayMode ([in] BMDDisplayMode displayMode, [out] IDeckLinkDisplayMode** resultDisplayMode); + HRESULT GetDisplayModeIterator ([out] IDeckLinkDisplayModeIterator** iterator); /* Video Input */ - HRESULT EnableVideoInput([in] BMDDisplayMode displayMode, [in] BMDPixelFormat pixelFormat, [in] BMDVideoInputFlags flags); - HRESULT DisableVideoInput(void); - HRESULT GetAvailablePacketsCount([out] unsigned int *availablePacketsCount); - HRESULT SetMemoryAllocator([in] IDeckLinkMemoryAllocator *theAllocator); + HRESULT EnableVideoInput ([in] BMDDisplayMode displayMode, [in] BMDPixelFormat pixelFormat, [in] BMDVideoInputFlags flags); + HRESULT DisableVideoInput (void); + HRESULT GetAvailablePacketsCount ([out] unsigned int* availablePacketsCount); + HRESULT SetMemoryAllocator ([in] IDeckLinkMemoryAllocator* theAllocator); /* Audio Input */ - HRESULT EnableAudioInput([in] BMDAudioFormat audioFormat, [in] BMDAudioSampleRate sampleRate, [in] BMDAudioSampleType sampleType, [in] unsigned int channelCount); - HRESULT DisableAudioInput(void); - HRESULT GetAvailableAudioSampleFrameCount([out] unsigned int *availableSampleFrameCount); + HRESULT EnableAudioInput ([in] BMDAudioFormat audioFormat, [in] BMDAudioSampleRate sampleRate, [in] BMDAudioSampleType sampleType, [in] unsigned int channelCount); + HRESULT DisableAudioInput (void); + HRESULT GetAvailableAudioSampleFrameCount ([out] unsigned int* availableSampleFrameCount); /* Input Control */ - HRESULT StartStreams(void); - HRESULT StopStreams(void); - HRESULT PauseStreams(void); - HRESULT FlushStreams(void); - HRESULT SetCallback([in] IDeckLinkEncoderInputCallback *theCallback); + HRESULT StartStreams (void); + HRESULT StopStreams (void); + HRESULT PauseStreams (void); + HRESULT FlushStreams (void); + HRESULT SetCallback ([in] IDeckLinkEncoderInputCallback* theCallback); /* Hardware Timing */ - HRESULT GetHardwareReferenceClock([in] BMDTimeScale desiredTimeScale, [out] BMDTimeValue *hardwareTime, [out] BMDTimeValue *timeInFrame, [out] BMDTimeValue *ticksPerFrame); + HRESULT GetHardwareReferenceClock ([in] BMDTimeScale desiredTimeScale, [out] BMDTimeValue* hardwareTime, [out] BMDTimeValue* timeInFrame, [out] BMDTimeValue* ticksPerFrame); }; /* Interface IDeckLinkVideoFrame - Interface to encapsulate a video frame; can be caller-implemented. */ @@ -830,19 +843,18 @@ interface IDeckLinkDiscovery; [ object, uuid(3F716FE0-F023-4111-BE5D-EF4414C05B17), - local, + local, helpstring("Interface to encapsulate a video frame; can be caller-implemented.") ] interface IDeckLinkVideoFrame : IUnknown { - long GetWidth(void); - long GetHeight(void); - long GetRowBytes(void); - BMDPixelFormat GetPixelFormat(void); - BMDFrameFlags GetFlags(void); - HRESULT GetBytes([out] void **buffer); - - HRESULT GetTimecode([in] BMDTimecodeFormat format, [out] IDeckLinkTimecode **timecode); - HRESULT GetAncillaryData([out] IDeckLinkVideoFrameAncillary **ancillary); // Use of IDeckLinkVideoFrameAncillaryPackets is preferred + long GetWidth (void); + long GetHeight (void); + long GetRowBytes (void); + BMDPixelFormat GetPixelFormat (void); + BMDFrameFlags GetFlags (void); + HRESULT GetBytes ([out] void** buffer); + HRESULT GetTimecode ([in] BMDTimecodeFormat format, [out] IDeckLinkTimecode** timecode); + HRESULT GetAncillaryData ([out] IDeckLinkVideoFrameAncillary** ancillary); // Use of IDeckLinkVideoFrameAncillaryPackets is preferred }; /* Interface IDeckLinkMutableVideoFrame - Created by IDeckLinkOutput::CreateVideoFrame. */ @@ -850,16 +862,15 @@ interface IDeckLinkDiscovery; [ object, uuid(69E2639F-40DA-4E19-B6F2-20ACE815C390), - local, + local, helpstring("Created by IDeckLinkOutput::CreateVideoFrame.") ] interface IDeckLinkMutableVideoFrame : IDeckLinkVideoFrame { - HRESULT SetFlags([in] BMDFrameFlags newFlags); - - HRESULT SetTimecode([in] BMDTimecodeFormat format, [in] IDeckLinkTimecode *timecode); - HRESULT SetTimecodeFromComponents([in] BMDTimecodeFormat format, [in] unsigned char hours, [in] unsigned char minutes, [in] unsigned char seconds, [in] unsigned char frames, [in] BMDTimecodeFlags flags); - HRESULT SetAncillaryData([in] IDeckLinkVideoFrameAncillary *ancillary); - HRESULT SetTimecodeUserBits([in] BMDTimecodeFormat format, [in] BMDTimecodeUserBits userBits); + HRESULT SetFlags ([in] BMDFrameFlags newFlags); + HRESULT SetTimecode ([in] BMDTimecodeFormat format, [in] IDeckLinkTimecode* timecode); + HRESULT SetTimecodeFromComponents ([in] BMDTimecodeFormat format, [in] unsigned char hours, [in] unsigned char minutes, [in] unsigned char seconds, [in] unsigned char frames, [in] BMDTimecodeFlags flags); + HRESULT SetAncillaryData ([in] IDeckLinkVideoFrameAncillary* ancillary); + HRESULT SetTimecodeUserBits ([in] BMDTimecodeFormat format, [in] BMDTimecodeUserBits userBits); }; /* Interface IDeckLinkVideoFrame3DExtensions - Optional interface implemented on IDeckLinkVideoFrame to support 3D frames */ @@ -867,27 +878,28 @@ interface IDeckLinkDiscovery; [ object, uuid(DA0F7E4A-EDC7-48A8-9CDD-2DB51C729CD7), - local, + local, helpstring("Optional interface implemented on IDeckLinkVideoFrame to support 3D frames") ] interface IDeckLinkVideoFrame3DExtensions : IUnknown { - BMDVideo3DPackingFormat Get3DPackingFormat(void); - HRESULT GetFrameForRightEye([out] IDeckLinkVideoFrame* *rightEyeFrame); + BMDVideo3DPackingFormat Get3DPackingFormat (void); + HRESULT GetFrameForRightEye ([out] IDeckLinkVideoFrame** rightEyeFrame); }; -/* Interface IDeckLinkVideoFrameMetadataExtensions - Optional interface implemented on IDeckLinkVideoFrame to support frame metadata such as HDMI HDR information */ +/* Interface IDeckLinkVideoFrameMetadataExtensions - Optional interface implemented on IDeckLinkVideoFrame to support frame metadata such as HDR information */ [ object, - uuid(D5973DC9-6432-46D0-8F0B-2496F8A1238F), - local, - helpstring("Optional interface implemented on IDeckLinkVideoFrame to support frame metadata such as HDMI HDR information") + uuid(E232A5B7-4DB4-44C9-9152-F47C12E5F051), + local, + helpstring("Optional interface implemented on IDeckLinkVideoFrame to support frame metadata such as HDR information") ] interface IDeckLinkVideoFrameMetadataExtensions : IUnknown { - HRESULT GetInt([in] BMDDeckLinkFrameMetadataID metadataID, [out] LONGLONG *value); - HRESULT GetFloat([in] BMDDeckLinkFrameMetadataID metadataID, [out] double *value); - HRESULT GetFlag([in] BMDDeckLinkFrameMetadataID metadataID, [out] BOOL* value); - HRESULT GetString([in] BMDDeckLinkFrameMetadataID metadataID, [out] BSTR *value); + HRESULT GetInt ([in] BMDDeckLinkFrameMetadataID metadataID, [out] LONGLONG* value); + HRESULT GetFloat ([in] BMDDeckLinkFrameMetadataID metadataID, [out] double* value); + HRESULT GetFlag ([in] BMDDeckLinkFrameMetadataID metadataID, [out] BOOL* value); + HRESULT GetString ([in] BMDDeckLinkFrameMetadataID metadataID, [out] BSTR* value); + HRESULT GetBytes ([in] BMDDeckLinkFrameMetadataID metadataID, [out] void* buffer /* optional */, [in, out] unsigned int* bufferSize); }; /* Interface IDeckLinkVideoInputFrame - Provided by the IDeckLinkVideoInput frame arrival callback. */ @@ -895,12 +907,12 @@ interface IDeckLinkDiscovery; [ object, uuid(05CFE374-537C-4094-9A57-680525118F44), - local, + local, helpstring("Provided by the IDeckLinkVideoInput frame arrival callback.") ] interface IDeckLinkVideoInputFrame : IDeckLinkVideoFrame { - HRESULT GetStreamTime([out] BMDTimeValue *frameTime, [out] BMDTimeValue *frameDuration, [in] BMDTimeScale timeScale); - HRESULT GetHardwareReferenceTimestamp([in] BMDTimeScale timeScale, [out] BMDTimeValue *frameTime, [out] BMDTimeValue *frameDuration); + HRESULT GetStreamTime ([out] BMDTimeValue* frameTime, [out] BMDTimeValue* frameDuration, [in] BMDTimeScale timeScale); + HRESULT GetHardwareReferenceTimestamp ([in] BMDTimeScale timeScale, [out] BMDTimeValue* frameTime, [out] BMDTimeValue* frameDuration); }; /* Interface IDeckLinkAncillaryPacket - On output, user needs to implement this interface */ @@ -911,12 +923,11 @@ interface IDeckLinkDiscovery; helpstring("On output, user needs to implement this interface") ] interface IDeckLinkAncillaryPacket : IUnknown { - - HRESULT GetBytes([in] BMDAncillaryPacketFormat format /* For output, only one format need be offered */, [out] const void **data /* Optional */, [out] unsigned int *size /* Optional */); - unsigned char GetDID(void); - unsigned char GetSDID(void); - unsigned int GetLineNumber(void); // On output, zero is auto - unsigned char GetDataStreamIndex(void); // Usually zero. Can only be 1 if non-SD and the first data stream is completely full + HRESULT GetBytes ([in] BMDAncillaryPacketFormat format /* For output, only one format need be offered */, [out] const void** data /* Optional */, [out] unsigned int* size /* Optional */); + unsigned char GetDID (void); + unsigned char GetSDID (void); + unsigned int GetLineNumber (void); // On output, zero is auto + unsigned char GetDataStreamIndex (void); // Usually zero. Can only be 1 if non-SD and the first data stream is completely full }; /* Interface IDeckLinkAncillaryPacketIterator - Enumerates ancillary packets */ @@ -927,39 +938,37 @@ interface IDeckLinkDiscovery; helpstring("Enumerates ancillary packets") ] interface IDeckLinkAncillaryPacketIterator : IUnknown { - HRESULT Next([out] IDeckLinkAncillaryPacket **packet); + HRESULT Next ([out] IDeckLinkAncillaryPacket** packet); }; -/* Interface IDeckLinkVideoFrameAncillaryPackets - Obtained through QueryInterface() on an IDeckLinkVideoFrame object. */ +/* Interface IDeckLinkVideoFrameAncillaryPackets - Obtained through QueryInterface on an IDeckLinkVideoFrame object. */ [ object, uuid(6C186C0F-459E-41D8-AEE2-4812D81AEE68), - local, - helpstring("Obtained through QueryInterface() on an IDeckLinkVideoFrame object.") + local, + helpstring("Obtained through QueryInterface on an IDeckLinkVideoFrame object.") ] interface IDeckLinkVideoFrameAncillaryPackets : IUnknown { - - HRESULT GetPacketIterator([out] IDeckLinkAncillaryPacketIterator **iterator); - HRESULT GetFirstPacketByID([in] unsigned char DID, [in] unsigned char SDID, [out] IDeckLinkAncillaryPacket **packet); - HRESULT AttachPacket([in] IDeckLinkAncillaryPacket *packet); // Implement IDeckLinkAncillaryPacket to output your own - HRESULT DetachPacket([in] IDeckLinkAncillaryPacket *packet); - HRESULT DetachAllPackets(void); + HRESULT GetPacketIterator ([out] IDeckLinkAncillaryPacketIterator** iterator); + HRESULT GetFirstPacketByID ([in] unsigned char DID, [in] unsigned char SDID, [out] IDeckLinkAncillaryPacket** packet); + HRESULT AttachPacket ([in] IDeckLinkAncillaryPacket* packet); // Implement IDeckLinkAncillaryPacket to output your own + HRESULT DetachPacket ([in] IDeckLinkAncillaryPacket* packet); + HRESULT DetachAllPackets (void); }; -/* Interface IDeckLinkVideoFrameAncillary - Use of IDeckLinkVideoFrameAncillaryPackets is preferred. Obtained through QueryInterface() on an IDeckLinkVideoFrame object. */ +/* Interface IDeckLinkVideoFrameAncillary - Use of IDeckLinkVideoFrameAncillaryPackets is preferred. Obtained through QueryInterface on an IDeckLinkVideoFrame object. */ [ object, uuid(732E723C-D1A4-4E29-9E8E-4A88797A0004), - local, - helpstring("Use of IDeckLinkVideoFrameAncillaryPackets is preferred. Obtained through QueryInterface() on an IDeckLinkVideoFrame object.") + local, + helpstring("Use of IDeckLinkVideoFrameAncillaryPackets is preferred. Obtained through QueryInterface on an IDeckLinkVideoFrame object.") ] interface IDeckLinkVideoFrameAncillary : IUnknown { - - HRESULT GetBufferForVerticalBlankingLine([in] unsigned int lineNumber, [out] void **buffer); // Pixels/rowbytes is same as display mode, except for above HD where it's 1920 pixels for UHD modes and 2048 pixels for DCI modes - BMDPixelFormat GetPixelFormat(void); - BMDDisplayMode GetDisplayMode(void); + HRESULT GetBufferForVerticalBlankingLine ([in] unsigned int lineNumber, [out] void** buffer); // Pixels/rowbytes is same as display mode, except for above HD where it's 1920 pixels for UHD modes and 2048 pixels for DCI modes + BMDPixelFormat GetPixelFormat (void); + BMDDisplayMode GetDisplayMode (void); }; /* Interface IDeckLinkEncoderPacket - Interface to encapsulate an encoded packet. */ @@ -967,14 +976,14 @@ interface IDeckLinkDiscovery; [ object, uuid(B693F36C-316E-4AF1-B6C2-F389A4BCA620), - local, + local, helpstring("Interface to encapsulate an encoded packet.") ] interface IDeckLinkEncoderPacket : IUnknown { - HRESULT GetBytes([out] void **buffer); - long GetSize(void); - HRESULT GetStreamTime([out] BMDTimeValue *frameTime, [in] BMDTimeScale timeScale); - BMDPacketType GetPacketType(void); + HRESULT GetBytes ([out] void** buffer); + long GetSize (void); + HRESULT GetStreamTime ([out] BMDTimeValue* frameTime, [in] BMDTimeScale timeScale); + BMDPacketType GetPacketType (void); }; /* Interface IDeckLinkEncoderVideoPacket - Provided by the IDeckLinkEncoderInput video packet arrival callback. */ @@ -982,14 +991,13 @@ interface IDeckLinkDiscovery; [ object, uuid(4E7FD944-E8C7-4EAC-B8C0-7B77F80F5AE0), - local, + local, helpstring("Provided by the IDeckLinkEncoderInput video packet arrival callback.") ] interface IDeckLinkEncoderVideoPacket : IDeckLinkEncoderPacket { - BMDPixelFormat GetPixelFormat(void); - HRESULT GetHardwareReferenceTimestamp([in] BMDTimeScale timeScale, [out] BMDTimeValue *frameTime, [out] BMDTimeValue *frameDuration); - - HRESULT GetTimecode([in] BMDTimecodeFormat format, [out] IDeckLinkTimecode **timecode); + BMDPixelFormat GetPixelFormat (void); + HRESULT GetHardwareReferenceTimestamp ([in] BMDTimeScale timeScale, [out] BMDTimeValue* frameTime, [out] BMDTimeValue* frameDuration); + HRESULT GetTimecode ([in] BMDTimecodeFormat format, [out] IDeckLinkTimecode** timecode); }; /* Interface IDeckLinkEncoderAudioPacket - Provided by the IDeckLinkEncoderInput audio packet arrival callback. */ @@ -997,25 +1005,25 @@ interface IDeckLinkDiscovery; [ object, uuid(49E8EDC8-693B-4E14-8EF6-12C658F5A07A), - local, + local, helpstring("Provided by the IDeckLinkEncoderInput audio packet arrival callback.") ] interface IDeckLinkEncoderAudioPacket : IDeckLinkEncoderPacket { - BMDAudioFormat GetAudioFormat(void); + BMDAudioFormat GetAudioFormat (void); }; -/* Interface IDeckLinkH265NALPacket - Obtained through QueryInterface() on an IDeckLinkEncoderVideoPacket object */ +/* Interface IDeckLinkH265NALPacket - Obtained through QueryInterface on an IDeckLinkEncoderVideoPacket object */ [ object, uuid(639C8E0B-68D5-4BDE-A6D4-95F3AEAFF2E7), - local, - helpstring("Obtained through QueryInterface() on an IDeckLinkEncoderVideoPacket object") + local, + helpstring("Obtained through QueryInterface on an IDeckLinkEncoderVideoPacket object") ] interface IDeckLinkH265NALPacket : IDeckLinkEncoderVideoPacket { - HRESULT GetUnitType([out] unsigned char *unitType); - HRESULT GetBytesNoPrefix([out] void **buffer); - long GetSizeNoPrefix(void); + HRESULT GetUnitType ([out] unsigned char* unitType); + HRESULT GetBytesNoPrefix ([out] void** buffer); + long GetSizeNoPrefix (void); }; /* Interface IDeckLinkAudioInputPacket - Provided by the IDeckLinkInput callback. */ @@ -1023,13 +1031,13 @@ interface IDeckLinkDiscovery; [ object, uuid(E43D5870-2894-11DE-8C30-0800200C9A66), - local, + local, helpstring("Provided by the IDeckLinkInput callback.") ] interface IDeckLinkAudioInputPacket : IUnknown { - long GetSampleFrameCount(void); - HRESULT GetBytes([out] void **buffer); - HRESULT GetPacketTime([out] BMDTimeValue *packetTime, [in] BMDTimeScale timeScale); + long GetSampleFrameCount (void); + HRESULT GetBytes ([out] void** buffer); + HRESULT GetPacketTime ([out] BMDTimeValue* packetTime, [in] BMDTimeScale timeScale); }; /* Interface IDeckLinkScreenPreviewCallback - Screen preview callback */ @@ -1037,44 +1045,44 @@ interface IDeckLinkDiscovery; [ object, uuid(B1D3F49A-85FE-4C5D-95C8-0B5D5DCCD438), - local, + local, helpstring("Screen preview callback") ] interface IDeckLinkScreenPreviewCallback : IUnknown { - HRESULT DrawFrame([in] IDeckLinkVideoFrame *theFrame); + HRESULT DrawFrame ([in] IDeckLinkVideoFrame* theFrame); }; -/* Interface IDeckLinkGLScreenPreviewHelper - Created with CoCreateInstance(). */ +/* Interface IDeckLinkGLScreenPreviewHelper - Created with CoCreateInstance on platforms with native COM support or from CreateOpenGLScreenPreviewHelper on other platforms. */ [ object, uuid(504E2209-CAC7-4C1A-9FB4-C5BB6274D22F), - local, - helpstring("Created with CoCreateInstance().") + local, + helpstring("Created with CoCreateInstance on platforms with native COM support or from CreateOpenGLScreenPreviewHelper on other platforms.") ] interface IDeckLinkGLScreenPreviewHelper : IUnknown { /* Methods must be called with OpenGL context set */ - HRESULT InitializeGL(void); - HRESULT PaintGL(void); - HRESULT SetFrame([in] IDeckLinkVideoFrame *theFrame); - HRESULT Set3DPreviewFormat([in] BMD3DPreviewFormat previewFormat); + HRESULT InitializeGL (void); + HRESULT PaintGL (void); + HRESULT SetFrame ([in] IDeckLinkVideoFrame* theFrame); + HRESULT Set3DPreviewFormat ([in] BMD3DPreviewFormat previewFormat); }; -/* Interface IDeckLinkDX9ScreenPreviewHelper - Created with CoCreateInstance(). */ +/* Interface IDeckLinkDX9ScreenPreviewHelper - Created with CoCreateInstance. */ [ object, uuid(2094B522-D1A1-40C0-9AC7-1C012218EF02), - local, - helpstring("Created with CoCreateInstance().") + local, + helpstring("Created with CoCreateInstance.") ] interface IDeckLinkDX9ScreenPreviewHelper : IUnknown { - HRESULT Initialize([in] void *device); - HRESULT Render([in] RECT *rc); - HRESULT SetFrame([in] IDeckLinkVideoFrame *theFrame); - HRESULT Set3DPreviewFormat([in] BMD3DPreviewFormat previewFormat); + HRESULT Initialize ([in] void* device); + HRESULT Render ([in] RECT* rc); + HRESULT SetFrame ([in] IDeckLinkVideoFrame* theFrame); + HRESULT Set3DPreviewFormat ([in] BMD3DPreviewFormat previewFormat); }; /* Interface IDeckLinkNotificationCallback - DeckLink Notification Callback Interface */ @@ -1082,39 +1090,90 @@ interface IDeckLinkDiscovery; [ object, uuid(b002a1ec-070d-4288-8289-bd5d36e5ff0d), - local, + local, helpstring("DeckLink Notification Callback Interface") ] interface IDeckLinkNotificationCallback : IUnknown { - HRESULT Notify([in] BMDNotifications topic, [in] ULONGLONG param1, [in] ULONGLONG param2); + HRESULT Notify ([in] BMDNotifications topic, [in] ULONGLONG param1, [in] ULONGLONG param2); }; /* Interface IDeckLinkNotification - DeckLink Notification interface */ [ object, - uuid(0a1fb207-e215-441b-9b19-6fa1575946c5), - local, + uuid(b85df4c8-bdf5-47c1-8064-28162ebdd4eb), + local, helpstring("DeckLink Notification interface") ] interface IDeckLinkNotification : IUnknown { - HRESULT Subscribe([in] BMDNotifications topic, [in] IDeckLinkNotificationCallback *theCallback); - HRESULT Unsubscribe([in] BMDNotifications topic, [in] IDeckLinkNotificationCallback *theCallback); + HRESULT Subscribe ([in] BMDNotifications topic, [in] IDeckLinkNotificationCallback* theCallback); + HRESULT Unsubscribe ([in] BMDNotifications topic, [in] IDeckLinkNotificationCallback* theCallback); }; -/* Interface IDeckLinkAttributes - DeckLink Attribute interface */ +/* Interface IDeckLinkProfileAttributes - Created by QueryInterface from an IDeckLinkProfile, or from IDeckLink. When queried from IDeckLink, interrogates the active profile */ [ object, - uuid(ABC11843-D966-44CB-96E2-A1CB5D3135C4), - local, - helpstring("DeckLink Attribute interface") -] interface IDeckLinkAttributes : IUnknown + uuid(17D4BF8E-4911-473A-80A0-731CF6FF345B), + local, + helpstring("Created by QueryInterface from an IDeckLinkProfile, or from IDeckLink. When queried from IDeckLink, interrogates the active profile") +] interface IDeckLinkProfileAttributes : IUnknown { - HRESULT GetFlag([in] BMDDeckLinkAttributeID cfgID, [out] BOOL *value); - HRESULT GetInt([in] BMDDeckLinkAttributeID cfgID, [out] LONGLONG *value); - HRESULT GetFloat([in] BMDDeckLinkAttributeID cfgID, [out] double *value); - HRESULT GetString([in] BMDDeckLinkAttributeID cfgID, [out] BSTR *value); + HRESULT GetFlag ([in] BMDDeckLinkAttributeID cfgID, [out] BOOL* value); + HRESULT GetInt ([in] BMDDeckLinkAttributeID cfgID, [out] LONGLONG* value); + HRESULT GetFloat ([in] BMDDeckLinkAttributeID cfgID, [out] double* value); + HRESULT GetString ([in] BMDDeckLinkAttributeID cfgID, [out] BSTR* value); +}; + +/* Interface IDeckLinkProfileIterator - Enumerates IDeckLinkProfile interfaces */ + +[ + object, + uuid(29E5A8C0-8BE4-46EB-93AC-31DAAB5B7BF2), + helpstring("Enumerates IDeckLinkProfile interfaces") +] interface IDeckLinkProfileIterator : IUnknown +{ + HRESULT Next ([out] IDeckLinkProfile** profile); +}; + +/* Interface IDeckLinkProfile - Represents the active profile when queried from IDeckLink */ + +[ + object, + uuid(16093466-674A-432B-9DA0-1AC2C5A8241C), + local, + helpstring("Represents the active profile when queried from IDeckLink") +] interface IDeckLinkProfile : IUnknown +{ + HRESULT GetDevice ([out] IDeckLink** device); // Device affected when this profile becomes active + HRESULT IsActive ([out] BOOL* isActive); + HRESULT SetActive (void); // Activating a profile will also change the profile on all devices enumerated by GetPeers. Activation is not complete until IDeckLinkProfileCallback::ProfileActivated is called + HRESULT GetPeers ([out] IDeckLinkProfileIterator** profileIterator); // Profiles of other devices activated with this profile +}; + +/* Interface IDeckLinkProfileCallback - Receive notifications about profiles related to this device */ + +[ + object, + uuid(A4F9341E-97AA-4E04-8935-15F809898CEA), + helpstring("Receive notifications about profiles related to this device") +] interface IDeckLinkProfileCallback : IUnknown +{ + HRESULT ProfileChanging ([in] IDeckLinkProfile* profileToBeActivated, [in] BOOL streamsWillBeForcedToStop); // Called before this device changes profile. User has an opportunity for teardown if streamsWillBeForcedToStop + HRESULT ProfileActivated ([in] IDeckLinkProfile* activatedProfile); // Called after this device has been activated with a new profile +}; + +/* Interface IDeckLinkProfileManager - Created by QueryInterface from IDeckLink when a device has multiple optional profiles */ + +[ + object, + uuid(30D41429-3998-4B6D-84F8-78C94A797C6E), + helpstring("Created by QueryInterface from IDeckLink when a device has multiple optional profiles") +] interface IDeckLinkProfileManager : IUnknown +{ + HRESULT GetProfiles ([out] IDeckLinkProfileIterator** profileIterator); // All available profiles for this device + HRESULT GetProfile ([in] BMDProfileID profileID, [out] IDeckLinkProfile** profile); + HRESULT SetCallback ([in] IDeckLinkProfileCallback* callback); }; /* Interface IDeckLinkStatus - DeckLink Status interface */ @@ -1122,15 +1181,15 @@ interface IDeckLinkDiscovery; [ object, uuid(5F558200-4028-49BC-BEAC-DB3FA4A96E46), - local, + local, helpstring("DeckLink Status interface") ] interface IDeckLinkStatus : IUnknown { - HRESULT GetFlag([in] BMDDeckLinkStatusID statusID, [out] BOOL *value); - HRESULT GetInt([in] BMDDeckLinkStatusID statusID, [out] LONGLONG *value); - HRESULT GetFloat([in] BMDDeckLinkStatusID statusID, [out] double *value); - HRESULT GetString([in] BMDDeckLinkStatusID statusID, [out] BSTR *value); - HRESULT GetBytes([in] BMDDeckLinkStatusID statusID, [out] void *buffer, [in, out] unsigned int *bufferSize); + HRESULT GetFlag ([in] BMDDeckLinkStatusID statusID, [out] BOOL* value); + HRESULT GetInt ([in] BMDDeckLinkStatusID statusID, [out] LONGLONG* value); + HRESULT GetFloat ([in] BMDDeckLinkStatusID statusID, [out] double* value); + HRESULT GetString ([in] BMDDeckLinkStatusID statusID, [out] BSTR* value); + HRESULT GetBytes ([in] BMDDeckLinkStatusID statusID, [out] void* buffer, [in, out] unsigned int* bufferSize); }; /* Interface IDeckLinkKeyer - DeckLink Keyer interface */ @@ -1138,27 +1197,27 @@ interface IDeckLinkDiscovery; [ object, uuid(89AFCAF5-65F8-421E-98F7-96FE5F5BFBA3), - local, + local, helpstring("DeckLink Keyer interface") ] interface IDeckLinkKeyer : IUnknown { - HRESULT Enable([in] BOOL isExternal); - HRESULT SetLevel([in] unsigned char level); - HRESULT RampUp([in] unsigned int numberOfFrames); - HRESULT RampDown([in] unsigned int numberOfFrames); - HRESULT Disable(void); + HRESULT Enable ([in] BOOL isExternal); + HRESULT SetLevel ([in] unsigned char level); + HRESULT RampUp ([in] unsigned int numberOfFrames); + HRESULT RampDown ([in] unsigned int numberOfFrames); + HRESULT Disable (void); }; -/* Interface IDeckLinkVideoConversion - Created with CoCreateInstance(). */ +/* Interface IDeckLinkVideoConversion - Created with CoCreateInstance. */ [ object, uuid(3BBCB8A2-DA2C-42D9-B5D8-88083644E99A), - local, - helpstring("Created with CoCreateInstance().") + local, + helpstring("Created with CoCreateInstance.") ] interface IDeckLinkVideoConversion : IUnknown { - HRESULT ConvertFrame([in] IDeckLinkVideoFrame* srcFrame, [in] IDeckLinkVideoFrame* dstFrame); + HRESULT ConvertFrame ([in] IDeckLinkVideoFrame* srcFrame, [in] IDeckLinkVideoFrame* dstFrame); }; /* Interface IDeckLinkDeviceNotificationCallback - DeckLink device arrival/removal notification callbacks */ @@ -1169,8 +1228,8 @@ interface IDeckLinkDiscovery; helpstring("DeckLink device arrival/removal notification callbacks") ] interface IDeckLinkDeviceNotificationCallback : IUnknown { - HRESULT DeckLinkDeviceArrived([in] IDeckLink* deckLinkDevice); - HRESULT DeckLinkDeviceRemoved([in] IDeckLink* deckLinkDevice); + HRESULT DeckLinkDeviceArrived ([in] IDeckLink* deckLinkDevice); + HRESULT DeckLinkDeviceRemoved ([in] IDeckLink* deckLinkDevice); }; /* Interface IDeckLinkDiscovery - DeckLink device discovery */ @@ -1181,8 +1240,8 @@ interface IDeckLinkDiscovery; helpstring("DeckLink device discovery") ] interface IDeckLinkDiscovery : IUnknown { - HRESULT InstallDeviceNotifications([in] IDeckLinkDeviceNotificationCallback* deviceNotificationCallback); - HRESULT UninstallDeviceNotifications(void); + HRESULT InstallDeviceNotifications ([in] IDeckLinkDeviceNotificationCallback* deviceNotificationCallback); + HRESULT UninstallDeviceNotifications (void); }; /* Coclasses */ @@ -1190,7 +1249,7 @@ interface IDeckLinkDiscovery; importlib("stdole2.tlb"); [ - uuid(87D2693F-8D4A-45C7-B43F-10ACBA25E68F), + uuid(BA6C6F44-6DA5-4DCE-94AA-EE2D1372A676), helpstring("CDeckLinkIterator Class") ] coclass CDeckLinkIterator { @@ -1230,7 +1289,7 @@ importlib("stdole2.tlb"); }; [ - uuid(652615D4-26CD-4514-B161-2FD5072ED008), + uuid(22FBFC33-8D07-495C-A5BF-DAB5EA9B82DB), helpstring("CDeckLinkDiscovery Class") ] coclass CDeckLinkDiscovery { @@ -1245,8 +1304,11 @@ importlib("stdole2.tlb"); [default] interface IDeckLinkVideoFrameAncillaryPackets; }; - // import deprecated interfaces +#include "DeckLinkAPI_v11_4.idl" +#include "DeckLinkAPI_v10_11.idl" +#include "DeckLinkAPI_v11_5_1.idl" +#include "DeckLinkAPI_v11_5.idl" #include "DeckLinkAPI_v10_9.idl" #include "DeckLinkAPIStreaming_v10_8.idl" #include "DeckLinkAPI_v10_8.idl" diff --git a/plugins/decklink/win/decklink-sdk/DeckLinkAPIConfiguration.idl b/plugins/decklink/win/decklink-sdk/DeckLinkAPIConfiguration.idl index 42a5234..e829d96 100644 --- a/plugins/decklink/win/decklink-sdk/DeckLinkAPIConfiguration.idl +++ b/plugins/decklink/win/decklink-sdk/DeckLinkAPIConfiguration.idl @@ -1,5 +1,5 @@ /* -LICENSE-START- -** Copyright (c) 2018 Blackmagic Design +** Copyright (c) 2020 Blackmagic Design ** ** Permission is hereby granted, free of charge, to any person or organization ** obtaining a copy of the software and accompanying documentation covered by @@ -7,14 +7,14 @@ ** execute, and transmit the Software, and to prepare derivative works of the ** Software, and to permit third-parties to whom the Software is furnished to ** do so, all subject to the following: -** +** ** The copyright notices in the Software and this entire statement, including ** the above license grant, this restriction and the following disclaimer, ** must be included in all copies of the Software, in whole or in part, and ** all derivative works of the Software, unless such copies or derivative ** works are solely in the form of machine-executable object code generated by ** a source language processor. -** +** ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT @@ -44,7 +44,7 @@ cpp_quote("#endif") /* Enum BMDDeckLinkConfigurationID - DeckLink Configuration ID */ -typedef [v1_enum] enum _BMDDeckLinkConfigurationID { +typedef [v1_enum] enum _BMDDeckLinkConfigurationID { /* Serial port Flags */ @@ -55,13 +55,14 @@ typedef [v1_enum] enum _BMDDeckLinkConfigurationID { bmdDeckLinkConfigHDMI3DPackingFormat = /* '3dpf' */ 0x33647066, bmdDeckLinkConfigBypass = /* 'byps' */ 0x62797073, bmdDeckLinkConfigClockTimingAdjustment = /* 'ctad' */ 0x63746164, - bmdDeckLinkConfigDuplexMode = /* 'dupx' */ 0x64757078, /* Audio Input/Output Flags */ bmdDeckLinkConfigAnalogAudioConsumerLevels = /* 'aacl' */ 0x6161636C, + bmdDeckLinkConfigSwapHDMICh3AndCh4OnInput = /* 'hi34' */ 0x68693334, + bmdDeckLinkConfigSwapHDMICh3AndCh4OnOutput = /* 'ho34' */ 0x686F3334, - /* Video output flags */ + /* Video Output Flags */ bmdDeckLinkConfigFieldFlickerRemoval = /* 'fdfr' */ 0x66646672, bmdDeckLinkConfigHD1080p24ToHD1080i5994Conversion = /* 'to59' */ 0x746F3539, @@ -72,9 +73,6 @@ typedef [v1_enum] enum _BMDDeckLinkConfigurationID { bmdDeckLinkConfigSMPTELevelAOutput = /* 'smta' */ 0x736D7461, bmdDeckLinkConfigRec2020Output = /* 'rec2' */ 0x72656332, // Ensure output is Rec.2020 colorspace bmdDeckLinkConfigQuadLinkSDIVideoOutputSquareDivisionSplit = /* 'SDQS' */ 0x53445153, - - /* Video Output Flags */ - bmdDeckLinkConfigOutput1080pAsPsF = /* 'pfpr' */ 0x70667072, /* Video Output Integers */ @@ -87,6 +85,8 @@ typedef [v1_enum] enum _BMDDeckLinkConfigurationID { bmdDeckLinkConfigDefaultVideoOutputMode = /* 'dvom' */ 0x64766F6D, bmdDeckLinkConfigDefaultVideoOutputModeFlags = /* 'dvof' */ 0x64766F66, bmdDeckLinkConfigSDIOutputLinkConfiguration = /* 'solc' */ 0x736F6C63, + bmdDeckLinkConfigHDMITimecodePacking = /* 'htpk' */ 0x6874706B, + bmdDeckLinkConfigPlaybackGroup = /* 'plgr' */ 0x706C6772, /* Video Output Floats */ @@ -103,9 +103,6 @@ typedef [v1_enum] enum _BMDDeckLinkConfigurationID { bmdDeckLinkConfigVideoInputScanning = /* 'visc' */ 0x76697363, // Applicable to H264 Pro Recorder only bmdDeckLinkConfigUseDedicatedLTCInput = /* 'dltc' */ 0x646C7463, // Use timecode from LTC input instead of SDI stream bmdDeckLinkConfigSDIInput3DPayloadOverride = /* '3dds' */ 0x33646473, - - /* Video Input Flags */ - bmdDeckLinkConfigCapture1080pAsPsF = /* 'cfpr' */ 0x63667072, /* Video Input Integers */ @@ -118,6 +115,7 @@ typedef [v1_enum] enum _BMDDeckLinkConfigurationID { bmdDeckLinkConfigVANCSourceLine2Mapping = /* 'vsl2' */ 0x76736C32, bmdDeckLinkConfigVANCSourceLine3Mapping = /* 'vsl3' */ 0x76736C33, bmdDeckLinkConfigCapturePassThroughMode = /* 'cptm' */ 0x6370746D, + bmdDeckLinkConfigCaptureGroup = /* 'cpgr' */ 0x63706772, /* Video Input Floats */ @@ -129,6 +127,10 @@ typedef [v1_enum] enum _BMDDeckLinkConfigurationID { bmdDeckLinkConfigVideoInputSVideoLumaGain = /* 'islg' */ 0x69736C67, bmdDeckLinkConfigVideoInputSVideoChromaGain = /* 'iscg' */ 0x69736367, + /* Keying Integers */ + + bmdDeckLinkConfigInternalKeyingAncillaryDataSource = /* 'ikas' */ 0x696B6173, + /* Audio Input Flags */ bmdDeckLinkConfigMicrophonePhantomPower = /* 'mphp' */ 0x6D706870, @@ -175,7 +177,7 @@ typedef [v1_enum] enum _BMDDeckLinkConfigurationID { /* Enum BMDDeckLinkEncoderConfigurationID - DeckLink Encoder Configuration ID */ -typedef [v1_enum] enum _BMDDeckLinkEncoderConfigurationID { +typedef [v1_enum] enum _BMDDeckLinkEncoderConfigurationID { /* Video Encoder Integers */ @@ -209,20 +211,20 @@ interface IDeckLinkEncoderConfiguration; [ object, - uuid(EF90380B-4AE5-4346-9077-E288E149F129), - local, + uuid(912F634B-2D4E-40A4-8AAB-8D80B73F1289), + local, helpstring("DeckLink Configuration interface") ] interface IDeckLinkConfiguration : IUnknown { - HRESULT SetFlag([in] BMDDeckLinkConfigurationID cfgID, [in] BOOL value); - HRESULT GetFlag([in] BMDDeckLinkConfigurationID cfgID, [out] BOOL *value); - HRESULT SetInt([in] BMDDeckLinkConfigurationID cfgID, [in] LONGLONG value); - HRESULT GetInt([in] BMDDeckLinkConfigurationID cfgID, [out] LONGLONG *value); - HRESULT SetFloat([in] BMDDeckLinkConfigurationID cfgID, [in] double value); - HRESULT GetFloat([in] BMDDeckLinkConfigurationID cfgID, [out] double *value); - HRESULT SetString([in] BMDDeckLinkConfigurationID cfgID, [in] BSTR value); - HRESULT GetString([in] BMDDeckLinkConfigurationID cfgID, [out] BSTR *value); - HRESULT WriteConfigurationToPreferences(void); + HRESULT SetFlag ([in] BMDDeckLinkConfigurationID cfgID, [in] BOOL value); + HRESULT GetFlag ([in] BMDDeckLinkConfigurationID cfgID, [out] BOOL* value); + HRESULT SetInt ([in] BMDDeckLinkConfigurationID cfgID, [in] LONGLONG value); + HRESULT GetInt ([in] BMDDeckLinkConfigurationID cfgID, [out] LONGLONG* value); + HRESULT SetFloat ([in] BMDDeckLinkConfigurationID cfgID, [in] double value); + HRESULT GetFloat ([in] BMDDeckLinkConfigurationID cfgID, [out] double* value); + HRESULT SetString ([in] BMDDeckLinkConfigurationID cfgID, [in] BSTR value); + HRESULT GetString ([in] BMDDeckLinkConfigurationID cfgID, [out] BSTR* value); + HRESULT WriteConfigurationToPreferences (void); }; /* Interface IDeckLinkEncoderConfiguration - DeckLink Encoder Configuration interface. Obtained from IDeckLinkEncoderInput */ @@ -230,23 +232,22 @@ interface IDeckLinkEncoderConfiguration; [ object, uuid(138050E5-C60A-4552-BF3F-0F358049327E), - local, + local, helpstring("DeckLink Encoder Configuration interface. Obtained from IDeckLinkEncoderInput") ] interface IDeckLinkEncoderConfiguration : IUnknown { - HRESULT SetFlag([in] BMDDeckLinkEncoderConfigurationID cfgID, [in] BOOL value); - HRESULT GetFlag([in] BMDDeckLinkEncoderConfigurationID cfgID, [out] BOOL *value); - HRESULT SetInt([in] BMDDeckLinkEncoderConfigurationID cfgID, [in] LONGLONG value); - HRESULT GetInt([in] BMDDeckLinkEncoderConfigurationID cfgID, [out] LONGLONG *value); - HRESULT SetFloat([in] BMDDeckLinkEncoderConfigurationID cfgID, [in] double value); - HRESULT GetFloat([in] BMDDeckLinkEncoderConfigurationID cfgID, [out] double *value); - HRESULT SetString([in] BMDDeckLinkEncoderConfigurationID cfgID, [in] BSTR value); - HRESULT GetString([in] BMDDeckLinkEncoderConfigurationID cfgID, [out] BSTR *value); - HRESULT GetBytes([in] BMDDeckLinkEncoderConfigurationID cfgID, [out] void *buffer /* optional */, [in, out] unsigned int *bufferSize); + HRESULT SetFlag ([in] BMDDeckLinkEncoderConfigurationID cfgID, [in] BOOL value); + HRESULT GetFlag ([in] BMDDeckLinkEncoderConfigurationID cfgID, [out] BOOL* value); + HRESULT SetInt ([in] BMDDeckLinkEncoderConfigurationID cfgID, [in] LONGLONG value); + HRESULT GetInt ([in] BMDDeckLinkEncoderConfigurationID cfgID, [out] LONGLONG* value); + HRESULT SetFloat ([in] BMDDeckLinkEncoderConfigurationID cfgID, [in] double value); + HRESULT GetFloat ([in] BMDDeckLinkEncoderConfigurationID cfgID, [out] double* value); + HRESULT SetString ([in] BMDDeckLinkEncoderConfigurationID cfgID, [in] BSTR value); + HRESULT GetString ([in] BMDDeckLinkEncoderConfigurationID cfgID, [out] BSTR* value); + HRESULT GetBytes ([in] BMDDeckLinkEncoderConfigurationID cfgID, [out] void* buffer /* optional */, [in, out] unsigned int* bufferSize); }; /* Coclasses */ importlib("stdole2.tlb"); - diff --git a/plugins/decklink/win/decklink-sdk/DeckLinkAPIDeckControl.idl b/plugins/decklink/win/decklink-sdk/DeckLinkAPIDeckControl.idl index ef85d82..464de8e 100644 --- a/plugins/decklink/win/decklink-sdk/DeckLinkAPIDeckControl.idl +++ b/plugins/decklink/win/decklink-sdk/DeckLinkAPIDeckControl.idl @@ -1,5 +1,5 @@ /* -LICENSE-START- -** Copyright (c) 2018 Blackmagic Design +** Copyright (c) 2020 Blackmagic Design ** ** Permission is hereby granted, free of charge, to any person or organization ** obtaining a copy of the software and accompanying documentation covered by @@ -7,14 +7,14 @@ ** execute, and transmit the Software, and to prepare derivative works of the ** Software, and to permit third-parties to whom the Software is furnished to ** do so, all subject to the following: -** +** ** The copyright notices in the Software and this entire statement, including ** the above license grant, this restriction and the following disclaimer, ** must be included in all copies of the Software, in whole or in part, and ** all derivative works of the Software, unless such copies or derivative ** works are solely in the form of machine-executable object code generated by ** a source language processor. -** +** ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT @@ -48,7 +48,7 @@ cpp_quote("#endif") /* Enum BMDDeckControlMode - DeckControl mode */ -typedef [v1_enum] enum _BMDDeckControlMode { +typedef [v1_enum] enum _BMDDeckControlMode { bmdDeckControlNotOpened = /* 'ntop' */ 0x6E746F70, bmdDeckControlVTRControlMode = /* 'vtrc' */ 0x76747263, bmdDeckControlExportMode = /* 'expm' */ 0x6578706D, @@ -57,23 +57,23 @@ typedef [v1_enum] enum _BMDDeckControlMode { /* Enum BMDDeckControlEvent - DeckControl event */ -typedef [v1_enum] enum _BMDDeckControlEvent { +typedef [v1_enum] enum _BMDDeckControlEvent { bmdDeckControlAbortedEvent = /* 'abte' */ 0x61627465, // This event is triggered when a capture or edit-to-tape operation is aborted. /* Export-To-Tape events */ - bmdDeckControlPrepareForExportEvent = /* 'pfee' */ 0x70666565, // This event is triggered a few frames before reaching the in-point. IDeckLinkInput::StartScheduledPlayback() should be called at this point. - bmdDeckControlExportCompleteEvent = /* 'exce' */ 0x65786365, // This event is triggered a few frames after reaching the out-point. At this point, it is safe to stop playback. + bmdDeckControlPrepareForExportEvent = /* 'pfee' */ 0x70666565, // This event is triggered a few frames before reaching the in-point. IDeckLinkInput::StartScheduledPlayback should be called at this point. + bmdDeckControlExportCompleteEvent = /* 'exce' */ 0x65786365, // This event is triggered a few frames after reaching the out-point. At this point, it is safe to stop playback. Upon reception of this event the deck's control mode is set back to bmdDeckControlVTRControlMode. /* Capture events */ bmdDeckControlPrepareForCaptureEvent = /* 'pfce' */ 0x70666365, // This event is triggered a few frames before reaching the in-point. The serial timecode attached to IDeckLinkVideoInputFrames is now valid. - bmdDeckControlCaptureCompleteEvent = /* 'ccev' */ 0x63636576 // This event is triggered a few frames after reaching the out-point. + bmdDeckControlCaptureCompleteEvent = /* 'ccev' */ 0x63636576 // This event is triggered a few frames after reaching the out-point. Upon reception of this event the deck's control mode is set back to bmdDeckControlVTRControlMode. } BMDDeckControlEvent; /* Enum BMDDeckControlVTRControlState - VTR Control state */ -typedef [v1_enum] enum _BMDDeckControlVTRControlState { +typedef [v1_enum] enum _BMDDeckControlVTRControlState { bmdDeckControlNotInVTRControlMode = /* 'nvcm' */ 0x6E76636D, bmdDeckControlVTRControlPlaying = /* 'vtrp' */ 0x76747270, bmdDeckControlVTRControlRecording = /* 'vtrr' */ 0x76747272, @@ -87,7 +87,7 @@ typedef [v1_enum] enum _BMDDeckControlVTRControlState { /* Enum BMDDeckControlStatusFlags - Deck Control status flags */ -[v1_enum] enum _BMDDeckControlStatusFlags { +[v1_enum] enum _BMDDeckControlStatusFlags { bmdDeckControlStatusDeckConnected = 1 << 0, bmdDeckControlStatusRemoteMode = 1 << 1, bmdDeckControlStatusRecordInhibited = 1 << 2, @@ -96,7 +96,7 @@ typedef [v1_enum] enum _BMDDeckControlVTRControlState { /* Enum BMDDeckControlExportModeOpsFlags - Export mode flags */ -[v1_enum] enum _BMDDeckControlExportModeOpsFlags { +[v1_enum] enum _BMDDeckControlExportModeOpsFlags { bmdDeckControlExportModeInsertVideo = 1 << 0, bmdDeckControlExportModeInsertAudio1 = 1 << 1, bmdDeckControlExportModeInsertAudio2 = 1 << 2, @@ -118,7 +118,7 @@ typedef [v1_enum] enum _BMDDeckControlVTRControlState { /* Enum BMDDeckControlError - Deck Control error */ -typedef [v1_enum] enum _BMDDeckControlError { +typedef [v1_enum] enum _BMDDeckControlError { bmdDeckControlNoError = /* 'noer' */ 0x6E6F6572, bmdDeckControlModeError = /* 'moer' */ 0x6D6F6572, bmdDeckControlMissedInPointError = /* 'mier' */ 0x6D696572, @@ -150,10 +150,10 @@ interface IDeckLinkDeckControl; helpstring("Deck control state change callback.") ] interface IDeckLinkDeckControlStatusCallback : IUnknown { - HRESULT TimecodeUpdate([in] BMDTimecodeBCD currentTimecode); - HRESULT VTRControlStateChanged([in] BMDDeckControlVTRControlState newState, [in] BMDDeckControlError error); - HRESULT DeckControlEventReceived([in] BMDDeckControlEvent event, [in] BMDDeckControlError error); - HRESULT DeckControlStatusChanged([in] BMDDeckControlStatusFlags flags, [in] unsigned int mask); + HRESULT TimecodeUpdate ([in] BMDTimecodeBCD currentTimecode); + HRESULT VTRControlStateChanged ([in] BMDDeckControlVTRControlState newState, [in] BMDDeckControlError error); + HRESULT DeckControlEventReceived ([in] BMDDeckControlEvent event, [in] BMDDeckControlError error); + HRESULT DeckControlStatusChanged ([in] BMDDeckControlStatusFlags flags, [in] unsigned int mask); }; /* Interface IDeckLinkDeckControl - Deck Control main interface */ @@ -164,43 +164,42 @@ interface IDeckLinkDeckControl; helpstring("Deck Control main interface") ] interface IDeckLinkDeckControl : IUnknown { - HRESULT Open([in] BMDTimeScale timeScale, [in] BMDTimeValue timeValue, [in] BOOL timecodeIsDropFrame, [out] BMDDeckControlError *error); - HRESULT Close([in] BOOL standbyOn); - HRESULT GetCurrentState([out] BMDDeckControlMode *mode, [out] BMDDeckControlVTRControlState *vtrControlState, [out] BMDDeckControlStatusFlags *flags); - HRESULT SetStandby([in] BOOL standbyOn); - HRESULT SendCommand([in] unsigned char *inBuffer, [in] unsigned int inBufferSize, [out] unsigned char *outBuffer, [out] unsigned int *outDataSize, [in] unsigned int outBufferSize, [out] BMDDeckControlError *error); - HRESULT Play([out] BMDDeckControlError *error); - HRESULT Stop([out] BMDDeckControlError *error); - HRESULT TogglePlayStop([out] BMDDeckControlError *error); - HRESULT Eject([out] BMDDeckControlError *error); - HRESULT GoToTimecode([in] BMDTimecodeBCD timecode, [out] BMDDeckControlError *error); - HRESULT FastForward([in] BOOL viewTape, [out] BMDDeckControlError *error); - HRESULT Rewind([in] BOOL viewTape, [out] BMDDeckControlError *error); - HRESULT StepForward([out] BMDDeckControlError *error); - HRESULT StepBack([out] BMDDeckControlError *error); - HRESULT Jog([in] double rate, [out] BMDDeckControlError *error); - HRESULT Shuttle([in] double rate, [out] BMDDeckControlError *error); - HRESULT GetTimecodeString([out] BSTR *currentTimeCode, [out] BMDDeckControlError *error); - HRESULT GetTimecode([out] IDeckLinkTimecode **currentTimecode, [out] BMDDeckControlError *error); - HRESULT GetTimecodeBCD([out] BMDTimecodeBCD *currentTimecode, [out] BMDDeckControlError *error); - HRESULT SetPreroll([in] unsigned int prerollSeconds); - HRESULT GetPreroll([out] unsigned int *prerollSeconds); - HRESULT SetExportOffset([in] int exportOffsetFields); - HRESULT GetExportOffset([out] int *exportOffsetFields); - HRESULT GetManualExportOffset([out] int *deckManualExportOffsetFields); - HRESULT SetCaptureOffset([in] int captureOffsetFields); - HRESULT GetCaptureOffset([out] int *captureOffsetFields); - HRESULT StartExport([in] BMDTimecodeBCD inTimecode, [in] BMDTimecodeBCD outTimecode, [in] BMDDeckControlExportModeOpsFlags exportModeOps, [out] BMDDeckControlError *error); - HRESULT StartCapture([in] BOOL useVITC, [in] BMDTimecodeBCD inTimecode, [in] BMDTimecodeBCD outTimecode, [out] BMDDeckControlError *error); - HRESULT GetDeviceID([out] unsigned short *deviceId, [out] BMDDeckControlError *error); - HRESULT Abort(void); - HRESULT CrashRecordStart([out] BMDDeckControlError *error); - HRESULT CrashRecordStop([out] BMDDeckControlError *error); - HRESULT SetCallback([in] IDeckLinkDeckControlStatusCallback *callback); + HRESULT Open ([in] BMDTimeScale timeScale, [in] BMDTimeValue timeValue, [in] BOOL timecodeIsDropFrame, [out] BMDDeckControlError* error); + HRESULT Close ([in] BOOL standbyOn); + HRESULT GetCurrentState ([out] BMDDeckControlMode* mode, [out] BMDDeckControlVTRControlState* vtrControlState, [out] BMDDeckControlStatusFlags* flags); + HRESULT SetStandby ([in] BOOL standbyOn); + HRESULT SendCommand ([in] unsigned char* inBuffer, [in] unsigned int inBufferSize, [out] unsigned char* outBuffer, [out] unsigned int* outDataSize, [in] unsigned int outBufferSize, [out] BMDDeckControlError* error); + HRESULT Play ([out] BMDDeckControlError* error); + HRESULT Stop ([out] BMDDeckControlError* error); + HRESULT TogglePlayStop ([out] BMDDeckControlError* error); + HRESULT Eject ([out] BMDDeckControlError* error); + HRESULT GoToTimecode ([in] BMDTimecodeBCD timecode, [out] BMDDeckControlError* error); + HRESULT FastForward ([in] BOOL viewTape, [out] BMDDeckControlError* error); + HRESULT Rewind ([in] BOOL viewTape, [out] BMDDeckControlError* error); + HRESULT StepForward ([out] BMDDeckControlError* error); + HRESULT StepBack ([out] BMDDeckControlError* error); + HRESULT Jog ([in] double rate, [out] BMDDeckControlError* error); + HRESULT Shuttle ([in] double rate, [out] BMDDeckControlError* error); + HRESULT GetTimecodeString ([out] BSTR* currentTimeCode, [out] BMDDeckControlError* error); + HRESULT GetTimecode ([out] IDeckLinkTimecode** currentTimecode, [out] BMDDeckControlError* error); + HRESULT GetTimecodeBCD ([out] BMDTimecodeBCD* currentTimecode, [out] BMDDeckControlError* error); + HRESULT SetPreroll ([in] unsigned int prerollSeconds); + HRESULT GetPreroll ([out] unsigned int* prerollSeconds); + HRESULT SetExportOffset ([in] int exportOffsetFields); + HRESULT GetExportOffset ([out] int* exportOffsetFields); + HRESULT GetManualExportOffset ([out] int* deckManualExportOffsetFields); + HRESULT SetCaptureOffset ([in] int captureOffsetFields); + HRESULT GetCaptureOffset ([out] int* captureOffsetFields); + HRESULT StartExport ([in] BMDTimecodeBCD inTimecode, [in] BMDTimecodeBCD outTimecode, [in] BMDDeckControlExportModeOpsFlags exportModeOps, [out] BMDDeckControlError* error); + HRESULT StartCapture ([in] BOOL useVITC, [in] BMDTimecodeBCD inTimecode, [in] BMDTimecodeBCD outTimecode, [out] BMDDeckControlError* error); + HRESULT GetDeviceID ([out] unsigned short* deviceId, [out] BMDDeckControlError* error); + HRESULT Abort (void); + HRESULT CrashRecordStart ([out] BMDDeckControlError* error); + HRESULT CrashRecordStop ([out] BMDDeckControlError* error); + HRESULT SetCallback ([in] IDeckLinkDeckControlStatusCallback* callback); }; /* Coclasses */ importlib("stdole2.tlb"); - diff --git a/plugins/decklink/win/decklink-sdk/DeckLinkAPIDiscovery.idl b/plugins/decklink/win/decklink-sdk/DeckLinkAPIDiscovery.idl index 66f65bc..419857a 100644 --- a/plugins/decklink/win/decklink-sdk/DeckLinkAPIDiscovery.idl +++ b/plugins/decklink/win/decklink-sdk/DeckLinkAPIDiscovery.idl @@ -1,5 +1,5 @@ /* -LICENSE-START- -** Copyright (c) 2018 Blackmagic Design +** Copyright (c) 2020 Blackmagic Design ** ** Permission is hereby granted, free of charge, to any person or organization ** obtaining a copy of the software and accompanying documentation covered by @@ -7,14 +7,14 @@ ** execute, and transmit the Software, and to prepare derivative works of the ** Software, and to permit third-parties to whom the Software is furnished to ** do so, all subject to the following: -** +** ** The copyright notices in the Software and this entire statement, including ** the above license grant, this restriction and the following disclaimer, ** must be included in all copies of the Software, in whole or in part, and ** all derivative works of the Software, unless such copies or derivative ** works are solely in the form of machine-executable object code generated by ** a source language processor. -** +** ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT @@ -46,20 +46,19 @@ cpp_quote("#endif") interface IDeckLink; -/* Interface IDeckLink - represents a DeckLink device */ +/* Interface IDeckLink - Represents a DeckLink device */ [ object, uuid(C418FBDD-0587-48ED-8FE5-640F0A14AF91), - helpstring("represents a DeckLink device") + helpstring("Represents a DeckLink device") ] interface IDeckLink : IUnknown { - HRESULT GetModelName([out] BSTR *modelName); - HRESULT GetDisplayName([out] BSTR *displayName); + HRESULT GetModelName ([out] BSTR* modelName); + HRESULT GetDisplayName ([out] BSTR* displayName); }; /* Coclasses */ importlib("stdole2.tlb"); - diff --git a/plugins/decklink/win/decklink-sdk/DeckLinkAPIModes.idl b/plugins/decklink/win/decklink-sdk/DeckLinkAPIModes.idl index 4e9eb26..cd73474 100644 --- a/plugins/decklink/win/decklink-sdk/DeckLinkAPIModes.idl +++ b/plugins/decklink/win/decklink-sdk/DeckLinkAPIModes.idl @@ -1,5 +1,5 @@ /* -LICENSE-START- -** Copyright (c) 2018 Blackmagic Design +** Copyright (c) 2020 Blackmagic Design ** ** Permission is hereby granted, free of charge, to any person or organization ** obtaining a copy of the software and accompanying documentation covered by @@ -7,14 +7,14 @@ ** execute, and transmit the Software, and to prepare derivative works of the ** Software, and to permit third-parties to whom the Software is furnished to ** do so, all subject to the following: -** +** ** The copyright notices in the Software and this entire statement, including ** the above license grant, this restriction and the following disclaimer, ** must be included in all copies of the Software, in whole or in part, and ** all derivative works of the Software, unless such copies or derivative ** works are solely in the form of machine-executable object code generated by ** a source language processor. -** +** ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT @@ -44,9 +44,9 @@ cpp_quote("#if 0") typedef enum _BMDDisplayModeFlags BMDDisplayModeFlags; cpp_quote("#endif") -/* Enum BMDDisplayMode - Video display modes */ +/* Enum BMDDisplayMode - BMDDisplayMode enumerates the video modes supported. */ -typedef [v1_enum] enum _BMDDisplayMode { +typedef [v1_enum] enum _BMDDisplayMode { /* SD Modes */ @@ -63,9 +63,16 @@ typedef [v1_enum] enum _BMDDisplayMode { bmdModeHD1080p25 = /* 'Hp25' */ 0x48703235, bmdModeHD1080p2997 = /* 'Hp29' */ 0x48703239, bmdModeHD1080p30 = /* 'Hp30' */ 0x48703330, + bmdModeHD1080p4795 = /* 'Hp47' */ 0x48703437, + bmdModeHD1080p48 = /* 'Hp48' */ 0x48703438, bmdModeHD1080p50 = /* 'Hp50' */ 0x48703530, bmdModeHD1080p5994 = /* 'Hp59' */ 0x48703539, bmdModeHD1080p6000 = /* 'Hp60' */ 0x48703630, // N.B. This _really_ is 60.00 Hz. + bmdModeHD1080p9590 = /* 'Hp95' */ 0x48703935, + bmdModeHD1080p96 = /* 'Hp96' */ 0x48703936, + bmdModeHD1080p100 = /* 'Hp10' */ 0x48703130, + bmdModeHD1080p11988 = /* 'Hp11' */ 0x48703131, + bmdModeHD1080p120 = /* 'Hp12' */ 0x48703132, bmdModeHD1080i50 = /* 'Hi50' */ 0x48693530, bmdModeHD1080i5994 = /* 'Hi59' */ 0x48693539, bmdModeHD1080i6000 = /* 'Hi60' */ 0x48693630, // N.B. This _really_ is 60.00 Hz. @@ -89,9 +96,16 @@ typedef [v1_enum] enum _BMDDisplayMode { bmdMode2kDCI25 = /* '2d25' */ 0x32643235, bmdMode2kDCI2997 = /* '2d29' */ 0x32643239, bmdMode2kDCI30 = /* '2d30' */ 0x32643330, + bmdMode2kDCI4795 = /* '2d47' */ 0x32643437, + bmdMode2kDCI48 = /* '2d48' */ 0x32643438, bmdMode2kDCI50 = /* '2d50' */ 0x32643530, bmdMode2kDCI5994 = /* '2d59' */ 0x32643539, bmdMode2kDCI60 = /* '2d60' */ 0x32643630, + bmdMode2kDCI9590 = /* '2d95' */ 0x32643935, + bmdMode2kDCI96 = /* '2d96' */ 0x32643936, + bmdMode2kDCI100 = /* '2d10' */ 0x32643130, + bmdMode2kDCI11988 = /* '2d11' */ 0x32643131, + bmdMode2kDCI120 = /* '2d12' */ 0x32643132, /* 4K UHD Modes */ @@ -100,9 +114,16 @@ typedef [v1_enum] enum _BMDDisplayMode { bmdMode4K2160p25 = /* '4k25' */ 0x346B3235, bmdMode4K2160p2997 = /* '4k29' */ 0x346B3239, bmdMode4K2160p30 = /* '4k30' */ 0x346B3330, + bmdMode4K2160p4795 = /* '4k47' */ 0x346B3437, + bmdMode4K2160p48 = /* '4k48' */ 0x346B3438, bmdMode4K2160p50 = /* '4k50' */ 0x346B3530, bmdMode4K2160p5994 = /* '4k59' */ 0x346B3539, bmdMode4K2160p60 = /* '4k60' */ 0x346B3630, + bmdMode4K2160p9590 = /* '4k95' */ 0x346B3935, + bmdMode4K2160p96 = /* '4k96' */ 0x346B3936, + bmdMode4K2160p100 = /* '4k10' */ 0x346B3130, + bmdMode4K2160p11988 = /* '4k11' */ 0x346B3131, + bmdMode4K2160p120 = /* '4k12' */ 0x346B3132, /* 4K DCI Modes */ @@ -111,9 +132,16 @@ typedef [v1_enum] enum _BMDDisplayMode { bmdMode4kDCI25 = /* '4d25' */ 0x34643235, bmdMode4kDCI2997 = /* '4d29' */ 0x34643239, bmdMode4kDCI30 = /* '4d30' */ 0x34643330, + bmdMode4kDCI4795 = /* '4d47' */ 0x34643437, + bmdMode4kDCI48 = /* '4d48' */ 0x34643438, bmdMode4kDCI50 = /* '4d50' */ 0x34643530, bmdMode4kDCI5994 = /* '4d59' */ 0x34643539, bmdMode4kDCI60 = /* '4d60' */ 0x34643630, + bmdMode4kDCI9590 = /* '4d95' */ 0x34643935, + bmdMode4kDCI96 = /* '4d96' */ 0x34643936, + bmdMode4kDCI100 = /* '4d10' */ 0x34643130, + bmdMode4kDCI11988 = /* '4d11' */ 0x34643131, + bmdMode4kDCI120 = /* '4d12' */ 0x34643132, /* 8K UHD Modes */ @@ -122,6 +150,8 @@ typedef [v1_enum] enum _BMDDisplayMode { bmdMode8K4320p25 = /* '8k25' */ 0x386B3235, bmdMode8K4320p2997 = /* '8k29' */ 0x386B3239, bmdMode8K4320p30 = /* '8k30' */ 0x386B3330, + bmdMode8K4320p4795 = /* '8k47' */ 0x386B3437, + bmdMode8K4320p48 = /* '8k48' */ 0x386B3438, bmdMode8K4320p50 = /* '8k50' */ 0x386B3530, bmdMode8K4320p5994 = /* '8k59' */ 0x386B3539, bmdMode8K4320p60 = /* '8k60' */ 0x386B3630, @@ -133,23 +163,39 @@ typedef [v1_enum] enum _BMDDisplayMode { bmdMode8kDCI25 = /* '8d25' */ 0x38643235, bmdMode8kDCI2997 = /* '8d29' */ 0x38643239, bmdMode8kDCI30 = /* '8d30' */ 0x38643330, + bmdMode8kDCI4795 = /* '8d47' */ 0x38643437, + bmdMode8kDCI48 = /* '8d48' */ 0x38643438, bmdMode8kDCI50 = /* '8d50' */ 0x38643530, bmdMode8kDCI5994 = /* '8d59' */ 0x38643539, bmdMode8kDCI60 = /* '8d60' */ 0x38643630, - /* RAW Modes for Cintel (input only) */ + /* PC Modes */ - bmdModeCintelRAW = /* 'rwci' */ 0x72776369, // Frame size up to 4096x3072, variable frame rate - bmdModeCintelCompressedRAW = /* 'rwcc' */ 0x72776363, // Frame size up to 4096x3072, variable frame rate + bmdMode640x480p60 = /* 'vga6' */ 0x76676136, + bmdMode800x600p60 = /* 'svg6' */ 0x73766736, + bmdMode1440x900p50 = /* 'wxg5' */ 0x77786735, + bmdMode1440x900p60 = /* 'wxg6' */ 0x77786736, + bmdMode1440x1080p50 = /* 'sxg5' */ 0x73786735, + bmdMode1440x1080p60 = /* 'sxg6' */ 0x73786736, + bmdMode1600x1200p50 = /* 'uxg5' */ 0x75786735, + bmdMode1600x1200p60 = /* 'uxg6' */ 0x75786736, + bmdMode1920x1200p50 = /* 'wux5' */ 0x77757835, + bmdMode1920x1200p60 = /* 'wux6' */ 0x77757836, + bmdMode1920x1440p50 = /* '1945' */ 0x31393435, + bmdMode1920x1440p60 = /* '1946' */ 0x31393436, + bmdMode2560x1440p50 = /* 'wqh5' */ 0x77716835, + bmdMode2560x1440p60 = /* 'wqh6' */ 0x77716836, + bmdMode2560x1600p50 = /* 'wqx5' */ 0x77717835, + bmdMode2560x1600p60 = /* 'wqx6' */ 0x77717836, /* Special Modes */ bmdModeUnknown = /* 'iunk' */ 0x69756E6B } BMDDisplayMode; -/* Enum BMDFieldDominance - Video field dominance */ +/* Enum BMDFieldDominance - BMDFieldDominance enumerates settings applicable to video fields. */ -typedef [v1_enum] enum _BMDFieldDominance { +typedef [v1_enum] enum _BMDFieldDominance { bmdUnknownFieldDominance = 0, bmdLowerFieldFirst = /* 'lowr' */ 0x6C6F7772, bmdUpperFieldFirst = /* 'uppr' */ 0x75707072, @@ -159,7 +205,8 @@ typedef [v1_enum] enum _BMDFieldDominance { /* Enum BMDPixelFormat - Video pixel formats supported for output/input */ -typedef [v1_enum] enum _BMDPixelFormat { +typedef [v1_enum] enum _BMDPixelFormat { + bmdFormatUnspecified = 0, bmdFormat8BitYUV = /* '2vuy' */ 0x32767579, bmdFormat10BitYUV = /* 'v210' */ 0x76323130, bmdFormat8BitARGB = 32, @@ -173,17 +220,12 @@ typedef [v1_enum] enum _BMDPixelFormat { /* AVID DNxHR */ - bmdFormatDNxHR = /* 'AVdh' */ 0x41566468, - - /* Cintel formats */ - - bmdFormat12BitRAWGRBG = /* 'r12p' */ 0x72313270, // 12-bit RAW data for bayer pattern GRBG - bmdFormat12BitRAWJPEG = /* 'r16p' */ 0x72313670 // 12-bit RAW data arranged in tiles and JPEG compressed + bmdFormatDNxHR = /* 'AVdh' */ 0x41566468 } BMDPixelFormat; /* Enum BMDDisplayModeFlags - Flags to describe the characteristics of an IDeckLinkDisplayMode. */ -[v1_enum] enum _BMDDisplayModeFlags { +[v1_enum] enum _BMDDisplayModeFlags { bmdDisplayModeSupports3D = 1 << 0, bmdDisplayModeColorspaceRec601 = 1 << 1, bmdDisplayModeColorspaceRec709 = 1 << 2, @@ -195,36 +237,35 @@ typedef [v1_enum] enum _BMDPixelFormat { interface IDeckLinkDisplayModeIterator; interface IDeckLinkDisplayMode; -/* Interface IDeckLinkDisplayModeIterator - enumerates over supported input/output display modes. */ +/* Interface IDeckLinkDisplayModeIterator - Enumerates over supported input/output display modes. */ [ object, uuid(9C88499F-F601-4021-B80B-032E4EB41C35), - helpstring("enumerates over supported input/output display modes.") + helpstring("Enumerates over supported input/output display modes.") ] interface IDeckLinkDisplayModeIterator : IUnknown { - HRESULT Next([out] IDeckLinkDisplayMode **deckLinkDisplayMode); + HRESULT Next ([out] IDeckLinkDisplayMode** deckLinkDisplayMode); }; -/* Interface IDeckLinkDisplayMode - represents a display mode */ +/* Interface IDeckLinkDisplayMode - Represents a display mode */ [ object, uuid(3EB2C1AB-0A3D-4523-A3AD-F40D7FB14E78), - helpstring("represents a display mode") + helpstring("Represents a display mode") ] interface IDeckLinkDisplayMode : IUnknown { - HRESULT GetName([out] BSTR *name); - BMDDisplayMode GetDisplayMode(void); - long GetWidth(void); - long GetHeight(void); - HRESULT GetFrameRate([out] BMDTimeValue *frameDuration, [out] BMDTimeScale *timeScale); - BMDFieldDominance GetFieldDominance(void); - BMDDisplayModeFlags GetFlags(void); + HRESULT GetName ([out] BSTR* name); + BMDDisplayMode GetDisplayMode (void); + long GetWidth (void); + long GetHeight (void); + HRESULT GetFrameRate ([out] BMDTimeValue* frameDuration, [out] BMDTimeScale* timeScale); + BMDFieldDominance GetFieldDominance (void); + BMDDisplayModeFlags GetFlags (void); }; /* Coclasses */ importlib("stdole2.tlb"); - diff --git a/plugins/decklink/win/decklink-sdk/DeckLinkAPIStreaming.idl b/plugins/decklink/win/decklink-sdk/DeckLinkAPIStreaming.idl index 56855fc..056e999 100644 --- a/plugins/decklink/win/decklink-sdk/DeckLinkAPIStreaming.idl +++ b/plugins/decklink/win/decklink-sdk/DeckLinkAPIStreaming.idl @@ -1,5 +1,5 @@ /* -LICENSE-START- -** Copyright (c) 2018 Blackmagic Design +** Copyright (c) 2020 Blackmagic Design ** ** Permission is hereby granted, free of charge, to any person or organization ** obtaining a copy of the software and accompanying documentation covered by @@ -7,14 +7,14 @@ ** execute, and transmit the Software, and to prepare derivative works of the ** Software, and to permit third-parties to whom the Software is furnished to ** do so, all subject to the following: -** +** ** The copyright notices in the Software and this entire statement, including ** the above license grant, this restriction and the following disclaimer, ** must be included in all copies of the Software, in whole or in part, and ** all derivative works of the Software, unless such copies or derivative ** works are solely in the form of machine-executable object code generated by ** a source language processor. -** +** ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT @@ -44,7 +44,7 @@ cpp_quote("#endif") /* Enum BMDStreamingDeviceMode - Device modes */ -typedef [v1_enum] enum _BMDStreamingDeviceMode { +typedef [v1_enum] enum _BMDStreamingDeviceMode { bmdStreamingDeviceIdle = /* 'idle' */ 0x69646C65, bmdStreamingDeviceEncoding = /* 'enco' */ 0x656E636F, bmdStreamingDeviceStopping = /* 'stop' */ 0x73746F70, @@ -53,7 +53,7 @@ typedef [v1_enum] enum _BMDStreamingDeviceMode { /* Enum BMDStreamingEncodingFrameRate - Encoded frame rates */ -typedef [v1_enum] enum _BMDStreamingEncodingFrameRate { +typedef [v1_enum] enum _BMDStreamingEncodingFrameRate { /* Interlaced rates */ @@ -75,21 +75,21 @@ typedef [v1_enum] enum _BMDStreamingEncodingFrameRate { /* Enum BMDStreamingEncodingSupport - Output encoding mode supported flag */ -typedef [v1_enum] enum _BMDStreamingEncodingSupport { +typedef [v1_enum] enum _BMDStreamingEncodingSupport { bmdStreamingEncodingModeNotSupported = 0, - bmdStreamingEncodingModeSupported, - bmdStreamingEncodingModeSupportedWithChanges + bmdStreamingEncodingModeSupported, + bmdStreamingEncodingModeSupportedWithChanges } BMDStreamingEncodingSupport; /* Enum BMDStreamingVideoCodec - Video codecs */ -typedef [v1_enum] enum _BMDStreamingVideoCodec { +typedef [v1_enum] enum _BMDStreamingVideoCodec { bmdStreamingVideoCodecH264 = /* 'H264' */ 0x48323634 } BMDStreamingVideoCodec; /* Enum BMDStreamingH264Profile - H264 encoding profile */ -typedef [v1_enum] enum _BMDStreamingH264Profile { +typedef [v1_enum] enum _BMDStreamingH264Profile { bmdStreamingH264ProfileHigh = /* 'high' */ 0x68696768, bmdStreamingH264ProfileMain = /* 'main' */ 0x6D61696E, bmdStreamingH264ProfileBaseline = /* 'base' */ 0x62617365 @@ -97,7 +97,7 @@ typedef [v1_enum] enum _BMDStreamingH264Profile { /* Enum BMDStreamingH264Level - H264 encoding level */ -typedef [v1_enum] enum _BMDStreamingH264Level { +typedef [v1_enum] enum _BMDStreamingH264Level { bmdStreamingH264Level12 = /* 'lv12' */ 0x6C763132, bmdStreamingH264Level13 = /* 'lv13' */ 0x6C763133, bmdStreamingH264Level2 = /* 'lv2 ' */ 0x6C763220, @@ -113,20 +113,20 @@ typedef [v1_enum] enum _BMDStreamingH264Level { /* Enum BMDStreamingH264EntropyCoding - H264 entropy coding */ -typedef [v1_enum] enum _BMDStreamingH264EntropyCoding { +typedef [v1_enum] enum _BMDStreamingH264EntropyCoding { bmdStreamingH264EntropyCodingCAVLC = /* 'EVLC' */ 0x45564C43, bmdStreamingH264EntropyCodingCABAC = /* 'EBAC' */ 0x45424143 } BMDStreamingH264EntropyCoding; /* Enum BMDStreamingAudioCodec - Audio codecs */ -typedef [v1_enum] enum _BMDStreamingAudioCodec { +typedef [v1_enum] enum _BMDStreamingAudioCodec { bmdStreamingAudioCodecAAC = /* 'AAC ' */ 0x41414320 } BMDStreamingAudioCodec; /* Enum BMDStreamingEncodingModePropertyID - Encoding mode properties */ -typedef [v1_enum] enum _BMDStreamingEncodingModePropertyID { +typedef [v1_enum] enum _BMDStreamingEncodingModePropertyID { /* Integers, Video Properties */ @@ -173,9 +173,9 @@ interface IBMDStreamingH264NALParser; helpstring("Device notification callbacks.") ] interface IBMDStreamingDeviceNotificationCallback : IUnknown { - HRESULT StreamingDeviceArrived([in] IDeckLink* device); - HRESULT StreamingDeviceRemoved([in] IDeckLink* device); - HRESULT StreamingDeviceModeChanged([in] IDeckLink* device, [in] BMDStreamingDeviceMode mode); + HRESULT StreamingDeviceArrived ([in] IDeckLink* device); + HRESULT StreamingDeviceRemoved ([in] IDeckLink* device); + HRESULT StreamingDeviceModeChanged ([in] IDeckLink* device, [in] BMDStreamingDeviceMode mode); }; /* Interface IBMDStreamingH264InputCallback - H264 input callbacks. */ @@ -186,12 +186,12 @@ interface IBMDStreamingH264NALParser; helpstring("H264 input callbacks.") ] interface IBMDStreamingH264InputCallback : IUnknown { - HRESULT H264NALPacketArrived([in] IBMDStreamingH264NALPacket* nalPacket); - HRESULT H264AudioPacketArrived([in] IBMDStreamingAudioPacket* audioPacket); - HRESULT MPEG2TSPacketArrived([in] IBMDStreamingMPEG2TSPacket* tsPacket); - HRESULT H264VideoInputConnectorScanningChanged(void); - HRESULT H264VideoInputConnectorChanged(void); - HRESULT H264VideoInputModeChanged(void); + HRESULT H264NALPacketArrived ([in] IBMDStreamingH264NALPacket* nalPacket); + HRESULT H264AudioPacketArrived ([in] IBMDStreamingAudioPacket* audioPacket); + HRESULT MPEG2TSPacketArrived ([in] IBMDStreamingMPEG2TSPacket* tsPacket); + HRESULT H264VideoInputConnectorScanningChanged (void); + HRESULT H264VideoInputConnectorChanged (void); + HRESULT H264VideoInputModeChanged (void); }; /* Interface IBMDStreamingDiscovery - Installs device notifications */ @@ -202,8 +202,8 @@ interface IBMDStreamingH264NALParser; helpstring("Installs device notifications") ] interface IBMDStreamingDiscovery : IUnknown { - HRESULT InstallDeviceNotifications([in] IBMDStreamingDeviceNotificationCallback* theCallback); - HRESULT UninstallDeviceNotifications(void); + HRESULT InstallDeviceNotifications ([in] IBMDStreamingDeviceNotificationCallback* theCallback); + HRESULT UninstallDeviceNotifications (void); }; /* Interface IBMDStreamingVideoEncodingMode - Represents an encoded video mode. */ @@ -214,19 +214,19 @@ interface IBMDStreamingH264NALParser; helpstring("Represents an encoded video mode.") ] interface IBMDStreamingVideoEncodingMode : IUnknown { - HRESULT GetName([out] BSTR *name); - unsigned int GetPresetID(void); - unsigned int GetSourcePositionX(void); - unsigned int GetSourcePositionY(void); - unsigned int GetSourceWidth(void); - unsigned int GetSourceHeight(void); - unsigned int GetDestWidth(void); - unsigned int GetDestHeight(void); - HRESULT GetFlag([in] BMDStreamingEncodingModePropertyID cfgID, [out] BOOL* value); - HRESULT GetInt([in] BMDStreamingEncodingModePropertyID cfgID, [out] LONGLONG* value); - HRESULT GetFloat([in] BMDStreamingEncodingModePropertyID cfgID, [out] double* value); - HRESULT GetString([in] BMDStreamingEncodingModePropertyID cfgID, [out] BSTR *value); - HRESULT CreateMutableVideoEncodingMode([out] IBMDStreamingMutableVideoEncodingMode** newEncodingMode); // Creates a mutable copy of the encoding mode + HRESULT GetName ([out] BSTR* name); + unsigned int GetPresetID (void); + unsigned int GetSourcePositionX (void); + unsigned int GetSourcePositionY (void); + unsigned int GetSourceWidth (void); + unsigned int GetSourceHeight (void); + unsigned int GetDestWidth (void); + unsigned int GetDestHeight (void); + HRESULT GetFlag ([in] BMDStreamingEncodingModePropertyID cfgID, [out] BOOL* value); + HRESULT GetInt ([in] BMDStreamingEncodingModePropertyID cfgID, [out] LONGLONG* value); + HRESULT GetFloat ([in] BMDStreamingEncodingModePropertyID cfgID, [out] double* value); + HRESULT GetString ([in] BMDStreamingEncodingModePropertyID cfgID, [out] BSTR* value); + HRESULT CreateMutableVideoEncodingMode ([out] IBMDStreamingMutableVideoEncodingMode** newEncodingMode); // Creates a mutable copy of the encoding mode }; /* Interface IBMDStreamingMutableVideoEncodingMode - Represents a mutable encoded video mode. */ @@ -237,12 +237,12 @@ interface IBMDStreamingH264NALParser; helpstring("Represents a mutable encoded video mode.") ] interface IBMDStreamingMutableVideoEncodingMode : IBMDStreamingVideoEncodingMode { - HRESULT SetSourceRect([in] unsigned int posX, [in] unsigned int posY, [in] unsigned int width, [in] unsigned int height); - HRESULT SetDestSize([in] unsigned int width, [in] unsigned int height); - HRESULT SetFlag([in] BMDStreamingEncodingModePropertyID cfgID, [in] BOOL value); - HRESULT SetInt([in] BMDStreamingEncodingModePropertyID cfgID, [in] LONGLONG value); - HRESULT SetFloat([in] BMDStreamingEncodingModePropertyID cfgID, [in] double value); - HRESULT SetString([in] BMDStreamingEncodingModePropertyID cfgID, [in] BSTR value); + HRESULT SetSourceRect ([in] unsigned int posX, [in] unsigned int posY, [in] unsigned int width, [in] unsigned int height); + HRESULT SetDestSize ([in] unsigned int width, [in] unsigned int height); + HRESULT SetFlag ([in] BMDStreamingEncodingModePropertyID cfgID, [in] BOOL value); + HRESULT SetInt ([in] BMDStreamingEncodingModePropertyID cfgID, [in] LONGLONG value); + HRESULT SetFloat ([in] BMDStreamingEncodingModePropertyID cfgID, [in] double value); + HRESULT SetString ([in] BMDStreamingEncodingModePropertyID cfgID, [in] BSTR value); }; /* Interface IBMDStreamingVideoEncodingModePresetIterator - Enumerates encoding mode presets */ @@ -253,7 +253,7 @@ interface IBMDStreamingH264NALParser; helpstring("Enumerates encoding mode presets") ] interface IBMDStreamingVideoEncodingModePresetIterator : IUnknown { - HRESULT Next([out] IBMDStreamingVideoEncodingMode** videoEncodingMode); + HRESULT Next ([out] IBMDStreamingVideoEncodingMode** videoEncodingMode); }; /* Interface IBMDStreamingDeviceInput - Created by QueryInterface from IDeckLink */ @@ -267,23 +267,23 @@ interface IBMDStreamingH264NALParser; /* Input modes */ - HRESULT DoesSupportVideoInputMode([in] BMDDisplayMode inputMode, [out] BOOL* result); - HRESULT GetVideoInputModeIterator([out] IDeckLinkDisplayModeIterator** iterator); - HRESULT SetVideoInputMode([in] BMDDisplayMode inputMode); - HRESULT GetCurrentDetectedVideoInputMode([out] BMDDisplayMode* detectedMode); + HRESULT DoesSupportVideoInputMode ([in] BMDDisplayMode inputMode, [out] BOOL* result); + HRESULT GetVideoInputModeIterator ([out] IDeckLinkDisplayModeIterator** iterator); + HRESULT SetVideoInputMode ([in] BMDDisplayMode inputMode); + HRESULT GetCurrentDetectedVideoInputMode ([out] BMDDisplayMode* detectedMode); /* Capture modes */ - HRESULT GetVideoEncodingMode([out] IBMDStreamingVideoEncodingMode** encodingMode); - HRESULT GetVideoEncodingModePresetIterator([in] BMDDisplayMode inputMode, [out] IBMDStreamingVideoEncodingModePresetIterator** iterator); - HRESULT DoesSupportVideoEncodingMode([in] BMDDisplayMode inputMode, [in] IBMDStreamingVideoEncodingMode* encodingMode, [out] BMDStreamingEncodingSupport* result, [out] IBMDStreamingVideoEncodingMode** changedEncodingMode); - HRESULT SetVideoEncodingMode([in] IBMDStreamingVideoEncodingMode* encodingMode); + HRESULT GetVideoEncodingMode ([out] IBMDStreamingVideoEncodingMode** encodingMode); + HRESULT GetVideoEncodingModePresetIterator ([in] BMDDisplayMode inputMode, [out] IBMDStreamingVideoEncodingModePresetIterator** iterator); + HRESULT DoesSupportVideoEncodingMode ([in] BMDDisplayMode inputMode, [in] IBMDStreamingVideoEncodingMode* encodingMode, [out] BMDStreamingEncodingSupport* result, [out] IBMDStreamingVideoEncodingMode** changedEncodingMode); + HRESULT SetVideoEncodingMode ([in] IBMDStreamingVideoEncodingMode* encodingMode); /* Input control */ - HRESULT StartCapture(void); - HRESULT StopCapture(void); - HRESULT SetCallback([in] IUnknown* theCallback); + HRESULT StartCapture (void); + HRESULT StopCapture (void); + HRESULT SetCallback ([in] IUnknown* theCallback); }; /* Interface IBMDStreamingH264NALPacket - Represent an H.264 NAL packet */ @@ -294,11 +294,11 @@ interface IBMDStreamingH264NALParser; helpstring("Represent an H.264 NAL packet") ] interface IBMDStreamingH264NALPacket : IUnknown { - long GetPayloadSize(void); - HRESULT GetBytes([out] void** buffer); - HRESULT GetBytesWithSizePrefix([out] void** buffer); // Contains a 32-bit unsigned big endian size prefix - HRESULT GetDisplayTime([in] ULONGLONG requestedTimeScale, [out] ULONGLONG* displayTime); - HRESULT GetPacketIndex([out] unsigned int* packetIndex); // Deprecated + long GetPayloadSize (void); + HRESULT GetBytes ([out] void** buffer); + HRESULT GetBytesWithSizePrefix ([out] void** buffer); // Contains a 32-bit unsigned big endian size prefix + HRESULT GetDisplayTime ([in] ULONGLONG requestedTimeScale, [out] ULONGLONG* displayTime); + HRESULT GetPacketIndex ([out] unsigned int* packetIndex); // Deprecated }; /* Interface IBMDStreamingAudioPacket - Represents a chunk of audio data */ @@ -309,11 +309,11 @@ interface IBMDStreamingH264NALParser; helpstring("Represents a chunk of audio data") ] interface IBMDStreamingAudioPacket : IUnknown { - BMDStreamingAudioCodec GetCodec(void); - long GetPayloadSize(void); - HRESULT GetBytes([out] void** buffer); - HRESULT GetPlayTime([in] ULONGLONG requestedTimeScale, [out] ULONGLONG* playTime); - HRESULT GetPacketIndex([out] unsigned int* packetIndex); // Deprecated + BMDStreamingAudioCodec GetCodec (void); + long GetPayloadSize (void); + HRESULT GetBytes ([out] void** buffer); + HRESULT GetPlayTime ([in] ULONGLONG requestedTimeScale, [out] ULONGLONG* playTime); + HRESULT GetPacketIndex ([out] unsigned int* packetIndex); // Deprecated }; /* Interface IBMDStreamingMPEG2TSPacket - Represent an MPEG2 Transport Stream packet */ @@ -324,8 +324,8 @@ interface IBMDStreamingH264NALParser; helpstring("Represent an MPEG2 Transport Stream packet") ] interface IBMDStreamingMPEG2TSPacket : IUnknown { - long GetPayloadSize(void); - HRESULT GetBytes([out] void** buffer); + long GetPayloadSize (void); + HRESULT GetBytes ([out] void** buffer); }; /* Interface IBMDStreamingH264NALParser - For basic NAL parsing */ @@ -336,9 +336,9 @@ interface IBMDStreamingH264NALParser; helpstring("For basic NAL parsing") ] interface IBMDStreamingH264NALParser : IUnknown { - HRESULT IsNALSequenceParameterSet([in] IBMDStreamingH264NALPacket* nal); - HRESULT IsNALPictureParameterSet([in] IBMDStreamingH264NALPacket* nal); - HRESULT GetProfileAndLevelFromSPS([in] IBMDStreamingH264NALPacket* nal, [out] unsigned int* profileIdc, [out] unsigned int* profileCompatability, [out] unsigned int* levelIdc); + HRESULT IsNALSequenceParameterSet ([in] IBMDStreamingH264NALPacket* nal); + HRESULT IsNALPictureParameterSet ([in] IBMDStreamingH264NALPacket* nal); + HRESULT GetProfileAndLevelFromSPS ([in] IBMDStreamingH264NALPacket* nal, [out] unsigned int* profileIdc, [out] unsigned int* profileCompatability, [out] unsigned int* levelIdc); }; /* Coclasses */ @@ -361,4 +361,3 @@ importlib("stdole2.tlb"); [default] interface IBMDStreamingH264NALParser; }; - diff --git a/plugins/decklink/win/decklink-sdk/DeckLinkAPITypes.idl b/plugins/decklink/win/decklink-sdk/DeckLinkAPITypes.idl index aeb52ab..527980d 100644 --- a/plugins/decklink/win/decklink-sdk/DeckLinkAPITypes.idl +++ b/plugins/decklink/win/decklink-sdk/DeckLinkAPITypes.idl @@ -1,5 +1,5 @@ /* -LICENSE-START- -** Copyright (c) 2018 Blackmagic Design +** Copyright (c) 2020 Blackmagic Design ** ** Permission is hereby granted, free of charge, to any person or organization ** obtaining a copy of the software and accompanying documentation covered by @@ -7,14 +7,14 @@ ** execute, and transmit the Software, and to prepare derivative works of the ** Software, and to permit third-parties to whom the Software is furnished to ** do so, all subject to the following: -** +** ** The copyright notices in the Software and this entire statement, including ** the above license grant, this restriction and the following disclaimer, ** must be included in all copies of the Software, in whole or in part, and ** all derivative works of the Software, unless such copies or derivative ** works are solely in the form of machine-executable object code generated by ** a source language processor. -** +** ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT @@ -50,16 +50,19 @@ cpp_quote("#endif") /* Enum BMDTimecodeFlags - Timecode flags */ -[v1_enum] enum _BMDTimecodeFlags { +[v1_enum] enum _BMDTimecodeFlags { bmdTimecodeFlagDefault = 0, bmdTimecodeIsDropFrame = 1 << 0, bmdTimecodeFieldMark = 1 << 1, - bmdTimecodeColorFrame = 1 << 2 + bmdTimecodeColorFrame = 1 << 2, + bmdTimecodeEmbedRecordingTrigger = 1 << 3, // On SDI recording trigger utilises a user-bit. + bmdTimecodeRecordingTriggered = 1 << 4 }; /* Enum BMDVideoConnection - Video connection types */ -typedef [v1_enum] enum _BMDVideoConnection { +typedef [v1_enum] enum _BMDVideoConnection { + bmdVideoConnectionUnspecified = 0, bmdVideoConnectionSDI = 1 << 0, bmdVideoConnectionHDMI = 1 << 1, bmdVideoConnectionOpticalSDI = 1 << 2, @@ -70,7 +73,7 @@ typedef [v1_enum] enum _BMDVideoConnection { /* Enum BMDAudioConnection - Audio connection types */ -typedef [v1_enum] enum _BMDAudioConnection { +typedef [v1_enum] enum _BMDAudioConnection { bmdAudioConnectionEmbedded = 1 << 0, bmdAudioConnectionAESEBU = 1 << 1, bmdAudioConnectionAnalog = 1 << 2, @@ -82,7 +85,7 @@ typedef [v1_enum] enum _BMDAudioConnection { /* Enum BMDDeckControlConnection - Deck control connections */ -typedef [v1_enum] enum _BMDDeckControlConnection { +typedef [v1_enum] enum _BMDDeckControlConnection { bmdDeckControlConnectionRS422Remote1 = 1 << 0, bmdDeckControlConnectionRS422Remote2 = 1 << 1 } BMDDeckControlConnection; @@ -99,15 +102,14 @@ interface IDeckLinkTimecode; helpstring("Used for video frame timecode representation.") ] interface IDeckLinkTimecode : IUnknown { - BMDTimecodeBCD GetBCD(void); - HRESULT GetComponents([out] unsigned char *hours, [out] unsigned char *minutes, [out] unsigned char *seconds, [out] unsigned char *frames); - HRESULT GetString([out] BSTR *timecode); - BMDTimecodeFlags GetFlags(void); - HRESULT GetTimecodeUserBits([out] BMDTimecodeUserBits *userBits); + BMDTimecodeBCD GetBCD (void); + HRESULT GetComponents ([out] unsigned char* hours, [out] unsigned char* minutes, [out] unsigned char* seconds, [out] unsigned char* frames); + HRESULT GetString ([out] BSTR* timecode); + BMDTimecodeFlags GetFlags (void); + HRESULT GetTimecodeUserBits ([out] BMDTimecodeUserBits* userBits); }; /* Coclasses */ importlib("stdole2.tlb"); - diff --git a/plugins/decklink/win/decklink-sdk/DeckLinkAPIVersion.h b/plugins/decklink/win/decklink-sdk/DeckLinkAPIVersion.h index f9db7ff..dcdeeb1 100644 --- a/plugins/decklink/win/decklink-sdk/DeckLinkAPIVersion.h +++ b/plugins/decklink/win/decklink-sdk/DeckLinkAPIVersion.h @@ -30,8 +30,8 @@ #ifndef __DeckLink_API_Version_h__ #define __DeckLink_API_Version_h__ -#define BLACKMAGIC_DECKLINK_API_VERSION 0x0a0b0400 -#define BLACKMAGIC_DECKLINK_API_VERSION_STRING "10.11.4" +#define BLACKMAGIC_DECKLINK_API_VERSION 0x0b060000 +#define BLACKMAGIC_DECKLINK_API_VERSION_STRING "11.6" #endif // __DeckLink_API_Version_h__ diff --git a/plugins/decklink/win/decklink-sdk/DeckLinkAPI_v10_11.idl b/plugins/decklink/win/decklink-sdk/DeckLinkAPI_v10_11.idl new file mode 100644 index 0000000..a3c0cb3 --- /dev/null +++ b/plugins/decklink/win/decklink-sdk/DeckLinkAPI_v10_11.idl @@ -0,0 +1,289 @@ +/* -LICENSE-START- +** Copyright (c) 2018 Blackmagic Design +** +** Permission is hereby granted, free of charge, to any person or organization +** obtaining a copy of the software and accompanying documentation covered by +** this license (the "Software") to use, reproduce, display, distribute, +** execute, and transmit the Software, and to prepare derivative works of the +** Software, and to permit third-parties to whom the Software is furnished to +** do so, all subject to the following: +** +** The copyright notices in the Software and this entire statement, including +** the above license grant, this restriction and the following disclaimer, +** must be included in all copies of the Software, in whole or in part, and +** all derivative works of the Software, unless such copies or derivative +** works are solely in the form of machine-executable object code generated by +** a source language processor. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +** SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +** FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +** DEALINGS IN THE SOFTWARE. +** -LICENSE-END- +*/ +/* DeckLinkAPI_v10_11.idl */ + +// Enumeration Mapping + +/* Enum BMDDisplayModeSupport_v10_11 - Output mode supported flags */ + +typedef [v1_enum] enum _BMDDisplayModeSupport_v10_11 { + bmdDisplayModeNotSupported_v10_11 = 0, + bmdDisplayModeSupported_v10_11, + bmdDisplayModeSupportedWithConversion_v10_11 +} BMDDisplayModeSupport_v10_11; + +/* Enum BMDDuplexMode - Duplex for configurable ports */ + +typedef [v1_enum] enum _BMDDuplexMode_v10_11 { + bmdDuplexModeFull_v10_11 = /* 'fdup' */ 0x66647570, + bmdDuplexModeHalf_v10_11 = /* 'hdup' */ 0x68647570 +} BMDDuplexMode_v10_11; + +/* Enum BMDDeckLinkConfigurationID - DeckLink Configuration ID */ + +typedef [v1_enum] enum _BMDDeckLinkConfigurationID_v10_11 { + + /* Video Input/Output Integers */ + + bmdDeckLinkConfigDuplexMode_v10_11 = /* 'dupx' */ 0x64757078, + +} BMDDeckLinkConfigurationID_v10_11; + +/* Enum BMDDeckLinkAttributeID - DeckLink Attribute ID */ + +typedef [v1_enum] enum _BMDDeckLinkAttributeID_v10_11 { + + /* Flags */ + + BMDDeckLinkSupportsDuplexModeConfiguration_v10_11 = /* 'dupx' */ 0x64757078, + BMDDeckLinkSupportsHDKeying_v10_11 = /* 'keyh' */ 0x6B657968, + + /* Integers */ + + BMDDeckLinkPairedDevicePersistentID_v10_11 = /* 'ppid' */ 0x70706964, + BMDDeckLinkSupportsFullDuplex_v10_11 = /* 'fdup' */ 0x66647570, + +} BMDDeckLinkAttributeID_v10_11; + +typedef [v1_enum] enum _BMDDeckLinkStatusID_v10_11 { + bmdDeckLinkStatusDuplexMode_v10_11 = /* 'dupx' */ 0x64757078, +} BMDDeckLinkStatusID_v10_11; + +/* Enum BMDDuplexStatus - Duplex status of the device */ + +typedef [v1_enum] enum _BMDDuplexStatus_v10_11 { + bmdDuplexFullDuplex_v10_11 = /* 'fdup' */ 0x66647570, + bmdDuplexHalfDuplex_v10_11 = /* 'hdup' */ 0x68647570, + bmdDuplexSimplex_v10_11 = /* 'splx' */ 0x73706C78, + bmdDuplexInactive_v10_11 = /* 'inac' */ 0x696E6163 +} BMDDuplexStatus_v10_11; + +// Forward Declarations + +interface IDeckLinkConfiguration_v10_11; +interface IDeckLinkAttributes_v10_11; +interface IDeckLinkNotification_v10_11; + +/* Interface IDeckLinkConfiguration_v10_11 - DeckLink Configuration interface */ + +[ + object, + uuid(EF90380B-4AE5-4346-9077-E288E149F129), + local, + helpstring("DeckLink Configuration interface") +] interface IDeckLinkConfiguration_v10_11 : IUnknown +{ + HRESULT SetFlag([in] BMDDeckLinkConfigurationID cfgID, [in] BOOL value); + HRESULT GetFlag([in] BMDDeckLinkConfigurationID cfgID, [out] BOOL *value); + HRESULT SetInt([in] BMDDeckLinkConfigurationID cfgID, [in] LONGLONG value); + HRESULT GetInt([in] BMDDeckLinkConfigurationID cfgID, [out] LONGLONG *value); + HRESULT SetFloat([in] BMDDeckLinkConfigurationID cfgID, [in] double value); + HRESULT GetFloat([in] BMDDeckLinkConfigurationID cfgID, [out] double *value); + HRESULT SetString([in] BMDDeckLinkConfigurationID cfgID, [in] BSTR value); + HRESULT GetString([in] BMDDeckLinkConfigurationID cfgID, [out] BSTR *value); + HRESULT WriteConfigurationToPreferences(void); +}; + +/* Interface IDeckLinkAttributes_v10_11 - DeckLink Attribute interface */ + +[ + object, + uuid(ABC11843-D966-44CB-96E2-A1CB5D3135C4), + local, + helpstring("DeckLink Attribute interface") +] interface IDeckLinkAttributes_v10_11 : IUnknown +{ + HRESULT GetFlag([in] BMDDeckLinkAttributeID cfgID, [out] BOOL *value); + HRESULT GetInt([in] BMDDeckLinkAttributeID cfgID, [out] LONGLONG *value); + HRESULT GetFloat([in] BMDDeckLinkAttributeID cfgID, [out] double *value); + HRESULT GetString([in] BMDDeckLinkAttributeID cfgID, [out] BSTR *value); +}; + +/* Interface IDeckLinkOutput_v10_11 - DeckLink output interface. */ + +[ + object, + uuid(CC5C8A6E-3F2F-4B3A-87EA-FD78AF300564), + local, + helpstring("Created by QueryInterface from IDeckLink.") +] interface IDeckLinkOutput_v10_11 : IUnknown +{ + HRESULT DoesSupportVideoMode([in] BMDDisplayMode displayMode, [in] BMDPixelFormat pixelFormat, [in] BMDVideoOutputFlags flags, [out] BMDDisplayModeSupport_v10_11 *result, [out] IDeckLinkDisplayMode **resultDisplayMode); + HRESULT GetDisplayModeIterator([out] IDeckLinkDisplayModeIterator **iterator); + + HRESULT SetScreenPreviewCallback([in] IDeckLinkScreenPreviewCallback *previewCallback); + + /* Video Output */ + + HRESULT EnableVideoOutput([in] BMDDisplayMode displayMode, [in] BMDVideoOutputFlags flags); + HRESULT DisableVideoOutput(void); + + HRESULT SetVideoOutputFrameMemoryAllocator([in] IDeckLinkMemoryAllocator *theAllocator); + HRESULT CreateVideoFrame([in] int width, [in] int height, [in] int rowBytes, [in] BMDPixelFormat pixelFormat, [in] BMDFrameFlags flags, [out] IDeckLinkMutableVideoFrame **outFrame); + HRESULT CreateAncillaryData([in] BMDPixelFormat pixelFormat, [out] IDeckLinkVideoFrameAncillary **outBuffer); + + HRESULT DisplayVideoFrameSync([in] IDeckLinkVideoFrame *theFrame); + HRESULT ScheduleVideoFrame([in] IDeckLinkVideoFrame *theFrame, [in] BMDTimeValue displayTime, [in] BMDTimeValue displayDuration, [in] BMDTimeScale timeScale); + HRESULT SetScheduledFrameCompletionCallback([in] IDeckLinkVideoOutputCallback *theCallback); + HRESULT GetBufferedVideoFrameCount([out] unsigned int *bufferedFrameCount); + + /* Audio Output */ + + HRESULT EnableAudioOutput([in] BMDAudioSampleRate sampleRate, [in] BMDAudioSampleType sampleType, [in] unsigned int channelCount, [in] BMDAudioOutputStreamType streamType); + HRESULT DisableAudioOutput(void); + + HRESULT WriteAudioSamplesSync([in] void *buffer, [in] unsigned int sampleFrameCount, [out] unsigned int *sampleFramesWritten); + + HRESULT BeginAudioPreroll(void); + HRESULT EndAudioPreroll(void); + HRESULT ScheduleAudioSamples([in] void *buffer, [in] unsigned int sampleFrameCount, [in] BMDTimeValue streamTime, [in] BMDTimeScale timeScale, [out] unsigned int *sampleFramesWritten); + + HRESULT GetBufferedAudioSampleFrameCount([out] unsigned int *bufferedSampleFrameCount); + HRESULT FlushBufferedAudioSamples(void); + + HRESULT SetAudioCallback([in] IDeckLinkAudioOutputCallback *theCallback); + + /* Output Control */ + + HRESULT StartScheduledPlayback([in] BMDTimeValue playbackStartTime, [in] BMDTimeScale timeScale, [in] double playbackSpeed); + HRESULT StopScheduledPlayback([in] BMDTimeValue stopPlaybackAtTime, [out] BMDTimeValue *actualStopTime, [in] BMDTimeScale timeScale); + HRESULT IsScheduledPlaybackRunning([out] BOOL *active); + HRESULT GetScheduledStreamTime([in] BMDTimeScale desiredTimeScale, [out] BMDTimeValue *streamTime, [out] double *playbackSpeed); + HRESULT GetReferenceStatus([out] BMDReferenceStatus *referenceStatus); + + /* Hardware Timing */ + + HRESULT GetHardwareReferenceClock([in] BMDTimeScale desiredTimeScale, [out] BMDTimeValue *hardwareTime, [out] BMDTimeValue *timeInFrame, [out] BMDTimeValue *ticksPerFrame); + HRESULT GetFrameCompletionReferenceTimestamp([in] IDeckLinkVideoFrame *theFrame, [in] BMDTimeScale desiredTimeScale, [out] BMDTimeValue *frameCompletionTimestamp); +}; + +/* Interface IDeckLinkInput_v10_11 - DeckLink input interface. */ + +[ + object, + uuid(AF22762B-DFAC-4846-AA79-FA8883560995), + helpstring("Created by QueryInterface from IDeckLink.") +] interface IDeckLinkInput_v10_11 : IUnknown +{ + HRESULT DoesSupportVideoMode([in] BMDDisplayMode displayMode, [in] BMDPixelFormat pixelFormat, [in] BMDVideoInputFlags flags, [out] BMDDisplayModeSupport_v10_11 *result, [out] IDeckLinkDisplayMode **resultDisplayMode); + HRESULT GetDisplayModeIterator([out] IDeckLinkDisplayModeIterator **iterator); + + HRESULT SetScreenPreviewCallback([in] IDeckLinkScreenPreviewCallback *previewCallback); + + /* Video Input */ + + HRESULT EnableVideoInput([in] BMDDisplayMode displayMode, [in] BMDPixelFormat pixelFormat, [in] BMDVideoInputFlags flags); + HRESULT DisableVideoInput(void); + HRESULT GetAvailableVideoFrameCount([out] unsigned int *availableFrameCount); + HRESULT SetVideoInputFrameMemoryAllocator([in] IDeckLinkMemoryAllocator *theAllocator); + + /* Audio Input */ + + HRESULT EnableAudioInput([in] BMDAudioSampleRate sampleRate, [in] BMDAudioSampleType sampleType, [in] unsigned int channelCount); + HRESULT DisableAudioInput(void); + HRESULT GetAvailableAudioSampleFrameCount([out] unsigned int *availableSampleFrameCount); + + /* Input Control */ + + HRESULT StartStreams(void); + HRESULT StopStreams(void); + HRESULT PauseStreams(void); + HRESULT FlushStreams(void); + HRESULT SetCallback([in] IDeckLinkInputCallback *theCallback); + + /* Hardware Timing */ + + HRESULT GetHardwareReferenceClock([in] BMDTimeScale desiredTimeScale, [out] BMDTimeValue *hardwareTime, [out] BMDTimeValue *timeInFrame, [out] BMDTimeValue *ticksPerFrame); +}; + +/* Interface IDeckLinkEncoderInput_v10_11 - Created by QueryInterface from IDeckLink. */ + +[ + object, + uuid(270587DA-6B7D-42E7-A1F0-6D853F581185), + helpstring("Created by QueryInterface from IDeckLink.") +] interface IDeckLinkEncoderInput_v10_11 : IUnknown +{ + HRESULT DoesSupportVideoMode([in] BMDDisplayMode displayMode, [in] BMDPixelFormat pixelFormat, [in] BMDVideoInputFlags flags, [out] BMDDisplayModeSupport_v10_11 *result, [out] IDeckLinkDisplayMode **resultDisplayMode); + HRESULT GetDisplayModeIterator([out] IDeckLinkDisplayModeIterator **iterator); + + /* Video Input */ + + HRESULT EnableVideoInput([in] BMDDisplayMode displayMode, [in] BMDPixelFormat pixelFormat, [in] BMDVideoInputFlags flags); + HRESULT DisableVideoInput(void); + HRESULT GetAvailablePacketsCount([out] unsigned int *availablePacketsCount); + HRESULT SetMemoryAllocator([in] IDeckLinkMemoryAllocator *theAllocator); + + /* Audio Input */ + + HRESULT EnableAudioInput([in] BMDAudioFormat audioFormat, [in] BMDAudioSampleRate sampleRate, [in] BMDAudioSampleType sampleType, [in] unsigned int channelCount); + HRESULT DisableAudioInput(void); + HRESULT GetAvailableAudioSampleFrameCount([out] unsigned int *availableSampleFrameCount); + + /* Input Control */ + + HRESULT StartStreams(void); + HRESULT StopStreams(void); + HRESULT PauseStreams(void); + HRESULT FlushStreams(void); + HRESULT SetCallback([in] IDeckLinkEncoderInputCallback *theCallback); + + /* Hardware Timing */ + + HRESULT GetHardwareReferenceClock([in] BMDTimeScale desiredTimeScale, [out] BMDTimeValue *hardwareTime, [out] BMDTimeValue *timeInFrame, [out] BMDTimeValue *ticksPerFrame); +}; + +/* Interface IDeckLinkNotification_v10_11 - DeckLink Notification interface */ + +[ + object, + uuid(0A1FB207-E215-441B-9B19-6FA1575946C5), + local, + helpstring("DeckLink Notification interface") +] interface IDeckLinkNotification_v10_11 : IUnknown +{ + HRESULT Subscribe([in] BMDNotifications topic, [in] IDeckLinkNotificationCallback *theCallback); + HRESULT Unsubscribe([in] BMDNotifications topic, [in] IDeckLinkNotificationCallback *theCallback); +}; + +importlib("stdole2.tlb"); + +[ + uuid(87D2693F-8D4A-45C7-B43F-10ACBA25E68F), + helpstring("CDeckLinkIterator_v10_11 Class") +] coclass CDeckLinkIterator_v10_11 +{ + [default] interface IDeckLinkIterator; +}; + +[ + uuid(652615D4-26CD-4514-B161-2FD5072ED008), + helpstring("CDeckLinkDiscovery_v10_11 Class") +] coclass CDeckLinkDiscovery_v10_11 +{ + [default] interface IDeckLinkDiscovery; +}; diff --git a/plugins/decklink/win/decklink-sdk/DeckLinkAPI_v11_4.idl b/plugins/decklink/win/decklink-sdk/DeckLinkAPI_v11_4.idl new file mode 100644 index 0000000..9db01b8 --- /dev/null +++ b/plugins/decklink/win/decklink-sdk/DeckLinkAPI_v11_4.idl @@ -0,0 +1,120 @@ +/* -LICENSE-START- +** Copyright (c) 2019 Blackmagic Design +** +** Permission is hereby granted, free of charge, to any person or organization +** obtaining a copy of the software and accompanying documentation covered by +** this license (the "Software") to use, reproduce, display, distribute, +** execute, and transmit the Software, and to prepare derivative works of the +** Software, and to permit third-parties to whom the Software is furnished to +** do so, all subject to the following: +** +** The copyright notices in the Software and this entire statement, including +** the above license grant, this restriction and the following disclaimer, +** must be included in all copies of the Software, in whole or in part, and +** all derivative works of the Software, unless such copies or derivative +** works are solely in the form of machine-executable object code generated by +** a source language processor. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +** SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +** FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +** DEALINGS IN THE SOFTWARE. +** -LICENSE-END- +*/ +/* DeckLinkAPI_v11_4.idl */ + +// Enumeration Mapping + +/* Interface IDeckLinkOutput_v11_4 - Created by QueryInterface from IDeckLink. */ + +[ + object, + uuid(065A0F6C-C508-4D0D-B919-F5EB0EBFC96B), + local, + helpstring("Created by QueryInterface from IDeckLink.") +] interface IDeckLinkOutput_v11_4 : IUnknown +{ + HRESULT DoesSupportVideoMode ([in] BMDVideoConnection connection /* If a value of 0 is specified, the caller does not care about the connection */, [in] BMDDisplayMode requestedMode, [in] BMDPixelFormat requestedPixelFormat, [in] BMDSupportedVideoModeFlags flags, [out] BMDDisplayMode* actualMode, [out] BOOL* supported); + HRESULT GetDisplayMode ([in] BMDDisplayMode displayMode, [out] IDeckLinkDisplayMode** resultDisplayMode); + HRESULT GetDisplayModeIterator ([out] IDeckLinkDisplayModeIterator** iterator); + HRESULT SetScreenPreviewCallback ([in] IDeckLinkScreenPreviewCallback* previewCallback); + + /* Video Output */ + + HRESULT EnableVideoOutput ([in] BMDDisplayMode displayMode, [in] BMDVideoOutputFlags flags); + HRESULT DisableVideoOutput (void); + HRESULT SetVideoOutputFrameMemoryAllocator ([in] IDeckLinkMemoryAllocator* theAllocator); + HRESULT CreateVideoFrame ([in] int width, [in] int height, [in] int rowBytes, [in] BMDPixelFormat pixelFormat, [in] BMDFrameFlags flags, [out] IDeckLinkMutableVideoFrame** outFrame); + HRESULT CreateAncillaryData ([in] BMDPixelFormat pixelFormat, [out] IDeckLinkVideoFrameAncillary** outBuffer); // Use of IDeckLinkVideoFrameAncillaryPackets is preferred + HRESULT DisplayVideoFrameSync ([in] IDeckLinkVideoFrame* theFrame); + HRESULT ScheduleVideoFrame ([in] IDeckLinkVideoFrame* theFrame, [in] BMDTimeValue displayTime, [in] BMDTimeValue displayDuration, [in] BMDTimeScale timeScale); + HRESULT SetScheduledFrameCompletionCallback ([in] IDeckLinkVideoOutputCallback* theCallback); + HRESULT GetBufferedVideoFrameCount ([out] unsigned int* bufferedFrameCount); + + /* Audio Output */ + + HRESULT EnableAudioOutput ([in] BMDAudioSampleRate sampleRate, [in] BMDAudioSampleType sampleType, [in] unsigned int channelCount, [in] BMDAudioOutputStreamType streamType); + HRESULT DisableAudioOutput (void); + HRESULT WriteAudioSamplesSync ([in] void* buffer, [in] unsigned int sampleFrameCount, [out] unsigned int* sampleFramesWritten); + HRESULT BeginAudioPreroll (void); + HRESULT EndAudioPreroll (void); + HRESULT ScheduleAudioSamples ([in] void* buffer, [in] unsigned int sampleFrameCount, [in] BMDTimeValue streamTime, [in] BMDTimeScale timeScale, [out] unsigned int* sampleFramesWritten); + HRESULT GetBufferedAudioSampleFrameCount ([out] unsigned int* bufferedSampleFrameCount); + HRESULT FlushBufferedAudioSamples (void); + HRESULT SetAudioCallback ([in] IDeckLinkAudioOutputCallback* theCallback); + + /* Output Control */ + + HRESULT StartScheduledPlayback ([in] BMDTimeValue playbackStartTime, [in] BMDTimeScale timeScale, [in] double playbackSpeed); + HRESULT StopScheduledPlayback ([in] BMDTimeValue stopPlaybackAtTime, [out] BMDTimeValue* actualStopTime, [in] BMDTimeScale timeScale); + HRESULT IsScheduledPlaybackRunning ([out] BOOL* active); + HRESULT GetScheduledStreamTime ([in] BMDTimeScale desiredTimeScale, [out] BMDTimeValue* streamTime, [out] double* playbackSpeed); + HRESULT GetReferenceStatus ([out] BMDReferenceStatus* referenceStatus); + + /* Hardware Timing */ + + HRESULT GetHardwareReferenceClock ([in] BMDTimeScale desiredTimeScale, [out] BMDTimeValue* hardwareTime, [out] BMDTimeValue* timeInFrame, [out] BMDTimeValue* ticksPerFrame); + HRESULT GetFrameCompletionReferenceTimestamp ([in] IDeckLinkVideoFrame* theFrame, [in] BMDTimeScale desiredTimeScale, [out] BMDTimeValue* frameCompletionTimestamp); +}; + +/* Interface IDeckLinkInput_v11_4 - Created by QueryInterface from IDeckLink. */ + +[ + object, + uuid(2A88CF76-F494-4216-A7EF-DC74EEB83882), + helpstring("Created by QueryInterface from IDeckLink.") +] interface IDeckLinkInput_v11_4 : IUnknown +{ + HRESULT DoesSupportVideoMode ([in] BMDVideoConnection connection /* If a value of 0 is specified, the caller does not care about the connection */, [in] BMDDisplayMode requestedMode, [in] BMDPixelFormat requestedPixelFormat, [in] BMDSupportedVideoModeFlags flags, [out] BOOL* supported); + HRESULT GetDisplayMode ([in] BMDDisplayMode displayMode, [out] IDeckLinkDisplayMode** resultDisplayMode); + HRESULT GetDisplayModeIterator ([out] IDeckLinkDisplayModeIterator** iterator); + HRESULT SetScreenPreviewCallback ([in] IDeckLinkScreenPreviewCallback* previewCallback); + + /* Video Input */ + + HRESULT EnableVideoInput ([in] BMDDisplayMode displayMode, [in] BMDPixelFormat pixelFormat, [in] BMDVideoInputFlags flags); + HRESULT DisableVideoInput (void); + HRESULT GetAvailableVideoFrameCount ([out] unsigned int* availableFrameCount); + HRESULT SetVideoInputFrameMemoryAllocator ([in] IDeckLinkMemoryAllocator* theAllocator); + + /* Audio Input */ + + HRESULT EnableAudioInput ([in] BMDAudioSampleRate sampleRate, [in] BMDAudioSampleType sampleType, [in] unsigned int channelCount); + HRESULT DisableAudioInput (void); + HRESULT GetAvailableAudioSampleFrameCount ([out] unsigned int* availableSampleFrameCount); + + /* Input Control */ + + HRESULT StartStreams (void); + HRESULT StopStreams (void); + HRESULT PauseStreams (void); + HRESULT FlushStreams (void); + HRESULT SetCallback ([in] IDeckLinkInputCallback* theCallback); + + /* Hardware Timing */ + + HRESULT GetHardwareReferenceClock ([in] BMDTimeScale desiredTimeScale, [out] BMDTimeValue* hardwareTime, [out] BMDTimeValue* timeInFrame, [out] BMDTimeValue* ticksPerFrame); +}; diff --git a/plugins/decklink/win/decklink-sdk/DeckLinkAPI_v11_5.idl b/plugins/decklink/win/decklink-sdk/DeckLinkAPI_v11_5.idl new file mode 100644 index 0000000..c03012c --- /dev/null +++ b/plugins/decklink/win/decklink-sdk/DeckLinkAPI_v11_5.idl @@ -0,0 +1,99 @@ +/* -LICENSE-START- +** Copyright (c) 2020 Blackmagic Design +** +** Permission is hereby granted, free of charge, to any person or organization +** obtaining a copy of the software and accompanying documentation covered by +** this license (the "Software") to use, reproduce, display, distribute, +** execute, and transmit the Software, and to prepare derivative works of the +** Software, and to permit third-parties to whom the Software is furnished to +** do so, all subject to the following: +** +** The copyright notices in the Software and this entire statement, including +** the above license grant, this restriction and the following disclaimer, +** must be included in all copies of the Software, in whole or in part, and +** all derivative works of the Software, unless such copies or derivative +** works are solely in the form of machine-executable object code generated by +** a source language processor. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +** SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +** FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +** DEALINGS IN THE SOFTWARE. +** -LICENSE-END- +*/ + +/* DeckLinkAPI_v11_5.idl */ + +typedef [v1_enum] enum _BMDDeckLinkFrameMetadataID_v11_5 { + bmdDeckLinkFrameMetadataCintelFilmType_v11_5 = /* 'cfty' */ 0x63667479, // Current film type + bmdDeckLinkFrameMetadataCintelFilmGauge_v11_5 = /* 'cfga' */ 0x63666761, // Current film gauge + bmdDeckLinkFrameMetadataCintelKeykodeLow_v11_5 = /* 'ckkl' */ 0x636B6B6C, // Raw keykode value - low 64 bits + bmdDeckLinkFrameMetadataCintelKeykodeHigh_v11_5 = /* 'ckkh' */ 0x636B6B68, // Raw keykode value - high 64 bits + bmdDeckLinkFrameMetadataCintelTile1Size_v11_5 = /* 'ct1s' */ 0x63743173, // Size in bytes of compressed raw tile 1 + bmdDeckLinkFrameMetadataCintelTile2Size_v11_5 = /* 'ct2s' */ 0x63743273, // Size in bytes of compressed raw tile 2 + bmdDeckLinkFrameMetadataCintelTile3Size_v11_5 = /* 'ct3s' */ 0x63743373, // Size in bytes of compressed raw tile 3 + bmdDeckLinkFrameMetadataCintelTile4Size_v11_5 = /* 'ct4s' */ 0x63743473, // Size in bytes of compressed raw tile 4 + bmdDeckLinkFrameMetadataCintelImageWidth_v11_5 = /* 'IWPx' */ 0x49575078, // Width in pixels of image + bmdDeckLinkFrameMetadataCintelImageHeight_v11_5 = /* 'IHPx' */ 0x49485078, // Height in pixels of image + bmdDeckLinkFrameMetadataCintelLinearMaskingRedInRed_v11_5 = /* 'mrir' */ 0x6D726972, // Red in red linear masking parameter + bmdDeckLinkFrameMetadataCintelLinearMaskingGreenInRed_v11_5 = /* 'mgir' */ 0x6D676972, // Green in red linear masking parameter + bmdDeckLinkFrameMetadataCintelLinearMaskingBlueInRed_v11_5 = /* 'mbir' */ 0x6D626972, // Blue in red linear masking parameter + bmdDeckLinkFrameMetadataCintelLinearMaskingRedInGreen_v11_5 = /* 'mrig' */ 0x6D726967, // Red in green linear masking parameter + bmdDeckLinkFrameMetadataCintelLinearMaskingGreenInGreen_v11_5 = /* 'mgig' */ 0x6D676967, // Green in green linear masking parameter + bmdDeckLinkFrameMetadataCintelLinearMaskingBlueInGreen_v11_5 = /* 'mbig' */ 0x6D626967, // Blue in green linear masking parameter + bmdDeckLinkFrameMetadataCintelLinearMaskingRedInBlue_v11_5 = /* 'mrib' */ 0x6D726962, // Red in blue linear masking parameter + bmdDeckLinkFrameMetadataCintelLinearMaskingGreenInBlue_v11_5 = /* 'mgib' */ 0x6D676962, // Green in blue linear masking parameter + bmdDeckLinkFrameMetadataCintelLinearMaskingBlueInBlue_v11_5 = /* 'mbib' */ 0x6D626962, // Blue in blue linear masking parameter + bmdDeckLinkFrameMetadataCintelLogMaskingRedInRed_v11_5 = /* 'mlrr' */ 0x6D6C7272, // Red in red log masking parameter + bmdDeckLinkFrameMetadataCintelLogMaskingGreenInRed_v11_5 = /* 'mlgr' */ 0x6D6C6772, // Green in red log masking parameter + bmdDeckLinkFrameMetadataCintelLogMaskingBlueInRed_v11_5 = /* 'mlbr' */ 0x6D6C6272, // Blue in red log masking parameter + bmdDeckLinkFrameMetadataCintelLogMaskingRedInGreen_v11_5 = /* 'mlrg' */ 0x6D6C7267, // Red in green log masking parameter + bmdDeckLinkFrameMetadataCintelLogMaskingGreenInGreen_v11_5 = /* 'mlgg' */ 0x6D6C6767, // Green in green log masking parameter + bmdDeckLinkFrameMetadataCintelLogMaskingBlueInGreen_v11_5 = /* 'mlbg' */ 0x6D6C6267, // Blue in green log masking parameter + bmdDeckLinkFrameMetadataCintelLogMaskingRedInBlue_v11_5 = /* 'mlrb' */ 0x6D6C7262, // Red in blue log masking parameter + bmdDeckLinkFrameMetadataCintelLogMaskingGreenInBlue_v11_5 = /* 'mlgb' */ 0x6D6C6762, // Green in blue log masking parameter + bmdDeckLinkFrameMetadataCintelLogMaskingBlueInBlue_v11_5 = /* 'mlbb' */ 0x6D6C6262, // Blue in blue log masking parameter + bmdDeckLinkFrameMetadataCintelFilmFrameRate_v11_5 = /* 'cffr' */ 0x63666672, // Film frame rate + bmdDeckLinkFrameMetadataCintelOffsetToApplyHorizontal_v11_5 = /* 'otah' */ 0x6F746168, // Horizontal offset (pixels) to be applied to image + bmdDeckLinkFrameMetadataCintelOffsetToApplyVertical_v11_5 = /* 'otav' */ 0x6F746176, // Vertical offset (pixels) to be applied to image + bmdDeckLinkFrameMetadataCintelGainRed_v11_5 = /* 'LfRd' */ 0x4C665264, // Red gain parameter to apply after log + bmdDeckLinkFrameMetadataCintelGainGreen_v11_5 = /* 'LfGr' */ 0x4C664772, // Green gain parameter to apply after log + bmdDeckLinkFrameMetadataCintelGainBlue_v11_5 = /* 'LfBl' */ 0x4C66426C, // Blue gain parameter to apply after log + bmdDeckLinkFrameMetadataCintelLiftRed_v11_5 = /* 'GnRd' */ 0x476E5264, // Red lift parameter to apply after log and gain + bmdDeckLinkFrameMetadataCintelLiftGreen_v11_5 = /* 'GnGr' */ 0x476E4772, // Green lift parameter to apply after log and gain + bmdDeckLinkFrameMetadataCintelLiftBlue_v11_5 = /* 'GnBl' */ 0x476E426C, // Blue lift parameter to apply after log and gain + bmdDeckLinkFrameMetadataCintelHDRGainRed_v11_5 = /* 'HGRd' */ 0x48475264, // Red gain parameter to apply to linear data for HDR Combination + bmdDeckLinkFrameMetadataCintelHDRGainGreen_v11_5 = /* 'HGGr' */ 0x48474772, // Green gain parameter to apply to linear data for HDR Combination + bmdDeckLinkFrameMetadataCintelHDRGainBlue_v11_5 = /* 'HGBl' */ 0x4847426C, // Blue gain parameter to apply to linear data for HDR Combination + bmdDeckLinkFrameMetadataCintel16mmCropRequired_v11_5 = /* 'c16c' */ 0x63313663, // The image should be cropped to 16mm size + bmdDeckLinkFrameMetadataCintelInversionRequired_v11_5 = /* 'cinv' */ 0x63696E76, // The image should be colour inverted + bmdDeckLinkFrameMetadataCintelFlipRequired_v11_5 = /* 'cflr' */ 0x63666C72, // The image should be flipped horizontally + bmdDeckLinkFrameMetadataCintelFocusAssistEnabled_v11_5 = /* 'cfae' */ 0x63666165, // Focus Assist is currently enabled + bmdDeckLinkFrameMetadataCintelKeykodeIsInterpolated_v11_5 = /* 'kkii' */ 0x6B6B6969 // The keykode for this frame is interpolated from nearby keykodes +} BMDDeckLinkFrameMetadataID_v11_5; + +// Forward Declarations + +interface IDeckLinkVideoFrameMetadataExtensions_v11_5; + +/* Interface IDeckLinkVideoFrameMetadataExtensions_v11_5 - Optional interface implemented on IDeckLinkVideoFrame to support frame metadata such as HDMI HDR information */ + +[ + object, + uuid(D5973DC9-6432-46D0-8F0B-2496F8A1238F), + local, + helpstring("Optional interface implemented on IDeckLinkVideoFrame to support frame metadata such as HDMI HDR information") +] interface IDeckLinkVideoFrameMetadataExtensions_v11_5 : IUnknown +{ + HRESULT GetInt([in] BMDDeckLinkFrameMetadataID_v11_5 metadataID, [out] LONGLONG *value); + HRESULT GetFloat([in] BMDDeckLinkFrameMetadataID_v11_5 metadataID, [out] double *value); + HRESULT GetFlag([in] BMDDeckLinkFrameMetadataID_v11_5 metadataID, [out] BOOL* value); + HRESULT GetString([in] BMDDeckLinkFrameMetadataID_v11_5 metadataID, [out] BSTR *value); +}; + +/* Coclasses */ + +importlib("stdole2.tlb"); diff --git a/plugins/decklink/win/decklink-sdk/DeckLinkAPI_v11_5_1.idl b/plugins/decklink/win/decklink-sdk/DeckLinkAPI_v11_5_1.idl new file mode 100644 index 0000000..485a73d --- /dev/null +++ b/plugins/decklink/win/decklink-sdk/DeckLinkAPI_v11_5_1.idl @@ -0,0 +1,90 @@ +/* -LICENSE-START- +** Copyright (c) 2020 Blackmagic Design +** +** Permission is hereby granted, free of charge, to any person or organization +** obtaining a copy of the software and accompanying documentation covered by +** this license (the "Software") to use, reproduce, display, distribute, +** execute, and transmit the Software, and to prepare derivative works of the +** Software, and to permit third-parties to whom the Software is furnished to +** do so, all subject to the following: +** +** The copyright notices in the Software and this entire statement, including +** the above license grant, this restriction and the following disclaimer, +** must be included in all copies of the Software, in whole or in part, and +** all derivative works of the Software, unless such copies or derivative +** works are solely in the form of machine-executable object code generated by +** a source language processor. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +** SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +** FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +** DEALINGS IN THE SOFTWARE. +** -LICENSE-END- +*/ +/* DeckLinkAPI_v11_5_1.idl */ + +// Enumeration Mapping + +/* Enum BMDDeckLinkStatusID - DeckLink Status ID */ + +typedef [v1_enum] enum _BMDDeckLinkStatusID_v11_5_1 { + + /* Video output flags */ + + bmdDeckLinkStatusDetectedVideoInputFlags_v11_5_1 = /* 'dvif' */ 0x64766966, + +} BMDDeckLinkStatusID_v11_5_1; + +/* Interface IDeckLinkInputCallback_v11_5_1 - Frame arrival callback. */ + +[ + object, + uuid(DD04E5EC-7415-42AB-AE4A-E80C4DFC044A), + helpstring("Frame arrival callback.") +] interface IDeckLinkInputCallback_v11_5_1 : IUnknown +{ + HRESULT VideoInputFormatChanged ([in] BMDVideoInputFormatChangedEvents notificationEvents, [in] IDeckLinkDisplayMode* newDisplayMode, [in] BMDDetectedVideoInputFormatFlags detectedSignalFlags); + HRESULT VideoInputFrameArrived ([in] IDeckLinkVideoInputFrame* videoFrame, [in] IDeckLinkAudioInputPacket* audioPacket); +}; + +/* Interface IDeckLinkInput_v11_5_1 - Created by QueryInterface from IDeckLink. */ + +[ + object, + uuid(9434C6E4-B15D-4B1C-979E-661E3DDCB4B9), + helpstring("Created by QueryInterface from IDeckLink.") +] interface IDeckLinkInput_v11_5_1 : IUnknown +{ + HRESULT DoesSupportVideoMode ([in] BMDVideoConnection connection /* If a value of bmdVideoConnectionUnspecified is specified, the caller does not care about the connection */, [in] BMDDisplayMode requestedMode, [in] BMDPixelFormat requestedPixelFormat, [in] BMDVideoInputConversionMode conversionMode, [in] BMDSupportedVideoModeFlags flags, [out] BMDDisplayMode* actualMode, [out] BOOL* supported); + HRESULT GetDisplayMode ([in] BMDDisplayMode displayMode, [out] IDeckLinkDisplayMode** resultDisplayMode); + HRESULT GetDisplayModeIterator ([out] IDeckLinkDisplayModeIterator** iterator); + HRESULT SetScreenPreviewCallback ([in] IDeckLinkScreenPreviewCallback* previewCallback); + + /* Video Input */ + + HRESULT EnableVideoInput ([in] BMDDisplayMode displayMode, [in] BMDPixelFormat pixelFormat, [in] BMDVideoInputFlags flags); + HRESULT DisableVideoInput (void); + HRESULT GetAvailableVideoFrameCount ([out] unsigned int* availableFrameCount); + HRESULT SetVideoInputFrameMemoryAllocator ([in] IDeckLinkMemoryAllocator* theAllocator); + + /* Audio Input */ + + HRESULT EnableAudioInput ([in] BMDAudioSampleRate sampleRate, [in] BMDAudioSampleType sampleType, [in] unsigned int channelCount); + HRESULT DisableAudioInput (void); + HRESULT GetAvailableAudioSampleFrameCount ([out] unsigned int* availableSampleFrameCount); + + /* Input Control */ + + HRESULT StartStreams (void); + HRESULT StopStreams (void); + HRESULT PauseStreams (void); + HRESULT FlushStreams (void); + HRESULT SetCallback ([in] IDeckLinkInputCallback_v11_5_1* theCallback); + + /* Hardware Timing */ + + HRESULT GetHardwareReferenceClock ([in] BMDTimeScale desiredTimeScale, [out] BMDTimeValue* hardwareTime, [out] BMDTimeValue* timeInFrame, [out] BMDTimeValue* ticksPerFrame); +}; \ No newline at end of file diff --git a/plugins/decklink/win/decklink-sdk/DeckLinkAPI_v7_1.idl b/plugins/decklink/win/decklink-sdk/DeckLinkAPI_v7_1.idl index 0fcc88e..e855671 100644 --- a/plugins/decklink/win/decklink-sdk/DeckLinkAPI_v7_1.idl +++ b/plugins/decklink/win/decklink-sdk/DeckLinkAPI_v7_1.idl @@ -70,7 +70,7 @@ helpstring("IDeckLinkOutput_v7_1. Created by QueryInterface from IDeckLink.")] interface IDeckLinkOutput_v7_1 : IUnknown { - HRESULT DoesSupportVideoMode (BMDDisplayMode displayMode, BMDPixelFormat pixelFormat, [out] BMDDisplayModeSupport *result); + HRESULT DoesSupportVideoMode (BMDDisplayMode displayMode, BMDPixelFormat pixelFormat, [out] BMDDisplayModeSupport_v10_11 *result); HRESULT GetDisplayModeIterator ([out] IDeckLinkDisplayModeIterator_v7_1 **iterator); // Video output @@ -110,7 +110,7 @@ helpstring("IDeckLinkInput_v7_1. Created by QueryInterface from IDeckLink.")] interface IDeckLinkInput_v7_1 : IUnknown { - HRESULT DoesSupportVideoMode (BMDDisplayMode displayMode, BMDPixelFormat pixelFormat, [out] BMDDisplayModeSupport *result); + HRESULT DoesSupportVideoMode (BMDDisplayMode displayMode, BMDPixelFormat pixelFormat, [out] BMDDisplayModeSupport_v10_11 *result); HRESULT GetDisplayModeIterator ([out] IDeckLinkDisplayModeIterator_v7_1 **iterator); // Video input diff --git a/plugins/decklink/win/decklink-sdk/DeckLinkAPI_v7_3.idl b/plugins/decklink/win/decklink-sdk/DeckLinkAPI_v7_3.idl index 3f3e00b..9fef249 100644 --- a/plugins/decklink/win/decklink-sdk/DeckLinkAPI_v7_3.idl +++ b/plugins/decklink/win/decklink-sdk/DeckLinkAPI_v7_3.idl @@ -59,7 +59,7 @@ interface IDeckLinkVideoInputFrame_v7_3; helpstring("Created by QueryInterface from IDeckLink.") ] interface IDeckLinkOutput_v7_3 : IUnknown { - HRESULT DoesSupportVideoMode(BMDDisplayMode displayMode, BMDPixelFormat pixelFormat, [out] BMDDisplayModeSupport *result); + HRESULT DoesSupportVideoMode(BMDDisplayMode displayMode, BMDPixelFormat pixelFormat, [out] BMDDisplayModeSupport_v10_11 *result); HRESULT GetDisplayModeIterator([out] IDeckLinkDisplayModeIterator_v7_6 **iterator); HRESULT SetScreenPreviewCallback([in] IDeckLinkScreenPreviewCallback *previewCallback); @@ -112,7 +112,7 @@ interface IDeckLinkVideoInputFrame_v7_3; helpstring("Created by QueryInterface from IDeckLink.") ] interface IDeckLinkInput_v7_3 : IUnknown { - HRESULT DoesSupportVideoMode(BMDDisplayMode displayMode, BMDPixelFormat pixelFormat, [out] BMDDisplayModeSupport *result); + HRESULT DoesSupportVideoMode(BMDDisplayMode displayMode, BMDPixelFormat pixelFormat, [out] BMDDisplayModeSupport_v10_11 *result); HRESULT GetDisplayModeIterator([out] IDeckLinkDisplayModeIterator_v7_6 **iterator); HRESULT SetScreenPreviewCallback([in] IDeckLinkScreenPreviewCallback *previewCallback); diff --git a/plugins/decklink/win/decklink-sdk/DeckLinkAPI_v7_6.idl b/plugins/decklink/win/decklink-sdk/DeckLinkAPI_v7_6.idl index c9b9b18..80df6b4 100644 --- a/plugins/decklink/win/decklink-sdk/DeckLinkAPI_v7_6.idl +++ b/plugins/decklink/win/decklink-sdk/DeckLinkAPI_v7_6.idl @@ -118,7 +118,7 @@ interface IDeckLinkConfiguration_v7_6; helpstring("Created by QueryInterface from IDeckLink.") ] interface IDeckLinkOutput_v7_6 : IUnknown { - HRESULT DoesSupportVideoMode(BMDDisplayMode displayMode, BMDPixelFormat pixelFormat, [out] BMDDisplayModeSupport *result); + HRESULT DoesSupportVideoMode(BMDDisplayMode displayMode, BMDPixelFormat pixelFormat, [out] BMDDisplayModeSupport_v10_11 *result); HRESULT GetDisplayModeIterator([out] IDeckLinkDisplayModeIterator_v7_6 **iterator); HRESULT SetScreenPreviewCallback([in] IDeckLinkScreenPreviewCallback_v7_6 *previewCallback); @@ -174,7 +174,7 @@ interface IDeckLinkConfiguration_v7_6; helpstring("Created by QueryInterface from IDeckLink.") ] interface IDeckLinkInput_v7_6 : IUnknown { - HRESULT DoesSupportVideoMode(BMDDisplayMode displayMode, BMDPixelFormat pixelFormat, [out] BMDDisplayModeSupport *result); + HRESULT DoesSupportVideoMode(BMDDisplayMode displayMode, BMDPixelFormat pixelFormat, [out] BMDDisplayModeSupport_v10_11 *result); HRESULT GetDisplayModeIterator([out] IDeckLinkDisplayModeIterator_v7_6 **iterator); HRESULT SetScreenPreviewCallback([in] IDeckLinkScreenPreviewCallback_v7_6 *previewCallback); diff --git a/plugins/decklink/win/decklink-sdk/DeckLinkAPI_v9_2.idl b/plugins/decklink/win/decklink-sdk/DeckLinkAPI_v9_2.idl index 6c6179a..a607d85 100644 --- a/plugins/decklink/win/decklink-sdk/DeckLinkAPI_v9_2.idl +++ b/plugins/decklink/win/decklink-sdk/DeckLinkAPI_v9_2.idl @@ -36,7 +36,7 @@ helpstring("Created by QueryInterface from IDeckLink.") ] interface IDeckLinkInput_v9_2 : IUnknown { - HRESULT DoesSupportVideoMode([in] BMDDisplayMode displayMode, [in] BMDPixelFormat pixelFormat, [in] BMDVideoInputFlags flags, [out] BMDDisplayModeSupport *result, [out] IDeckLinkDisplayMode **resultDisplayMode); + HRESULT DoesSupportVideoMode([in] BMDDisplayMode displayMode, [in] BMDPixelFormat pixelFormat, [in] BMDVideoInputFlags flags, [out] BMDDisplayModeSupport_v10_11 *result, [out] IDeckLinkDisplayMode **resultDisplayMode); HRESULT GetDisplayModeIterator([out] IDeckLinkDisplayModeIterator **iterator); HRESULT SetScreenPreviewCallback([in] IDeckLinkScreenPreviewCallback *previewCallback); diff --git a/plugins/decklink/win/decklink-sdk/DeckLinkAPI_v9_9.idl b/plugins/decklink/win/decklink-sdk/DeckLinkAPI_v9_9.idl index c908e42..ece3bff 100644 --- a/plugins/decklink/win/decklink-sdk/DeckLinkAPI_v9_9.idl +++ b/plugins/decklink/win/decklink-sdk/DeckLinkAPI_v9_9.idl @@ -37,7 +37,7 @@ helpstring("Created by QueryInterface from IDeckLink.") ] interface IDeckLinkOutput_v9_9 : IUnknown { - HRESULT DoesSupportVideoMode([in] BMDDisplayMode displayMode, [in] BMDPixelFormat pixelFormat, [in] BMDVideoOutputFlags flags, [out] BMDDisplayModeSupport *result, [out] IDeckLinkDisplayMode **resultDisplayMode); + HRESULT DoesSupportVideoMode([in] BMDDisplayMode displayMode, [in] BMDPixelFormat pixelFormat, [in] BMDVideoOutputFlags flags, [out] BMDDisplayModeSupport_v10_11 *result, [out] IDeckLinkDisplayMode **resultDisplayMode); HRESULT GetDisplayModeIterator([out] IDeckLinkDisplayModeIterator **iterator); HRESULT SetScreenPreviewCallback([in] IDeckLinkScreenPreviewCallback *previewCallback); diff --git a/plugins/decklink/win/platform.cpp b/plugins/decklink/win/platform.cpp index 260797d..59e0721 100644 --- a/plugins/decklink/win/platform.cpp +++ b/plugins/decklink/win/platform.cpp @@ -20,6 +20,16 @@ IDeckLinkIterator *CreateDeckLinkIteratorInstance(void) return result == S_OK ? iterator : nullptr; } +IDeckLinkVideoConversion *CreateVideoConversionInstance(void) +{ + IDeckLinkVideoConversion *conversion; + const HRESULT result = CoCreateInstance(CLSID_CDeckLinkVideoConversion, + nullptr, CLSCTX_ALL, + IID_IDeckLinkVideoConversion, + (void **)&conversion); + return result == S_OK ? conversion : nullptr; +} + bool DeckLinkStringToStdString(decklink_string_t input, std::string &output) { if (input == nullptr) diff --git a/plugins/image-source/data/locale/az-AZ.ini b/plugins/image-source/data/locale/az-AZ.ini new file mode 100644 index 0000000..e35e217 --- /dev/null +++ b/plugins/image-source/data/locale/az-AZ.ini @@ -0,0 +1,36 @@ +ImageInput="Təsvir" +File="Təsvir faylı" +UnloadWhenNotShowing="Göstərilməyəndə təsviri çıxart" + +SlideShow="Təsvir Slayd Şousu" +SlideShow.TransitionSpeed="Keçid sürəti (millisaniyə)" +SlideShow.SlideTime="Slaydlar arası vaxt (millisaniyə)" +SlideShow.Files="Təsvir faylları" +SlideShow.CustomSize="Məhdudlaşdırıcı ölçü/Əmsal nisbəti" +SlideShow.CustomSize.Auto="Avtomatik" +SlideShow.Randomize="Təsadüfi göstərmə" +SlideShow.Loop="Dövr" +SlideShow.Transition="Keçid" +SlideShow.Transition.Cut="Kəs" +SlideShow.Transition.Fade="Solma" +SlideShow.Transition.Swipe="Swipe" +SlideShow.Transition.Slide="Slide" +SlideShow.PlaybackBehavior="Görünmə Davranışı" +SlideShow.PlaybackBehavior.StopRestart="Görünməyəndə dayandır, görünəndə yenidən başlat" +SlideShow.PlaybackBehavior.PauseUnpause="Görünməyəndə fasilə ver, görünəndə oynat" +SlideShow.PlaybackBehavior.AlwaysPlay="Görünməyəndə belə həmişə oynat" +SlideShow.SlideMode="Slayd rejimi" +SlideShow.SlideMode.Auto="Avtomatik" +SlideShow.SlideMode.Manual="Əllə (slayd şouya nəzarət etmək üçün qısayol düymələrini istifadə et)" +SlideShow.PlayPause="Oynat/Fasilə ver" +SlideShow.Restart="Yenidən başlat" +SlideShow.Stop="Dayandır" +SlideShow.NextSlide="Növbəti slayd" +SlideShow.PreviousSlide="Əvvəlki slayd" +SlideShow.HideWhenDone="Slayd şou hazır olanda gizlət" + +ColorSource="Rəng mənbəsi" +ColorSource.Color="Rəng" +ColorSource.Width="Eni" +ColorSource.Height="Hündürlüyü" + diff --git a/plugins/image-source/data/locale/et-EE.ini b/plugins/image-source/data/locale/et-EE.ini index cec51a4..0c1e395 100644 --- a/plugins/image-source/data/locale/et-EE.ini +++ b/plugins/image-source/data/locale/et-EE.ini @@ -14,9 +14,16 @@ SlideShow.Transition.Cut="Ilmuv" SlideShow.Transition.Fade="Hajuv" SlideShow.Transition.Swipe="Pühkiv" SlideShow.Transition.Slide="Sisselendav" +SlideShow.PlaybackBehavior="Nähtav käitumine" +SlideShow.PlaybackBehavior.StopRestart="Lõpeta kui nähtamatu, alusta uuesti kui nähtav" +SlideShow.PlaybackBehavior.PauseUnpause="Peata kui nähtamatu, jätka kui nähtav" SlideShow.PlaybackBehavior.AlwaysPlay="Mängi alati, isegi siis kui pole nähtav" SlideShow.SlideMode.Auto="Automaatne" SlideShow.PlayPause="Esita/Peata" +SlideShow.Restart="Taaskäivita" +SlideShow.Stop="Lõpeta" +SlideShow.NextSlide="Järgmine slaid" +SlideShow.PreviousSlide="Eelmine slaid" ColorSource="Värvi allikas" ColorSource.Color="Värv" diff --git a/plugins/image-source/data/locale/fa-IR.ini b/plugins/image-source/data/locale/fa-IR.ini index ae1e29a..d0c39cb 100644 --- a/plugins/image-source/data/locale/fa-IR.ini +++ b/plugins/image-source/data/locale/fa-IR.ini @@ -6,6 +6,7 @@ SlideShow="نمایش اسلایدی تصویر" SlideShow.TransitionSpeed="سرعت انتقال (میلی ثانیه)" SlideShow.SlideTime="زمان بین اسلاید (میلی ثانیه)" SlideShow.Files="پوشه تصاویر" +SlideShow.CustomSize="نسبت اندازه/نسبت ابعاد" SlideShow.CustomSize.Auto="خودکار" SlideShow.Randomize="پخش تصادفی" SlideShow.Loop="چرخه" @@ -17,8 +18,10 @@ SlideShow.Transition.Slide="اسلاید" SlideShow.PlaybackBehavior="کنش های دیداری" SlideShow.PlaybackBehavior.StopRestart="توقف زمانی که قابل مشاهده نیست، راه اندازی مجدد زمانی که قابل مشاهده است" SlideShow.PlaybackBehavior.PauseUnpause="توقف زمانی که قابل مشاهده نیست، راه اندازی مجدد زمانی که قابل مشاهده است" +SlideShow.PlaybackBehavior.AlwaysPlay="همیشه حتی وقتی دیده نمی شود اجرا کنید" SlideShow.SlideMode="حالت اسلاید" SlideShow.SlideMode.Auto="خودکار" +SlideShow.SlideMode.Manual="دستی (از کلیدهای میانبر برای کنترل نمایش اسلاید استفاده کنید)" SlideShow.PlayPause="پخش/توقف" SlideShow.Restart="راه اندازی مجدد" SlideShow.Stop="توقف" diff --git a/plugins/image-source/data/locale/he-IL.ini b/plugins/image-source/data/locale/he-IL.ini index 23cfd73..dd95bd7 100644 --- a/plugins/image-source/data/locale/he-IL.ini +++ b/plugins/image-source/data/locale/he-IL.ini @@ -6,15 +6,19 @@ SlideShow="מצגת תמונות" SlideShow.TransitionSpeed="מהירות מעבר (אלפיות שניה)" SlideShow.SlideTime="זמן בין שקופיות (אלפיות שניה)" SlideShow.Files="קבצי תמונה" +SlideShow.CustomSize="גודל הצמדה\יחס גובה-רוחב" SlideShow.CustomSize.Auto="אוטומטי" SlideShow.Randomize="סדר נגינה אקראי" +SlideShow.Loop="לולאה" SlideShow.Transition="מעבר" SlideShow.Transition.Cut="חתוך" SlideShow.Transition.Fade="עמעום" SlideShow.Transition.Swipe="החלקה" SlideShow.Transition.Slide="הסט" SlideShow.PlaybackBehavior="התנהגות ניראות" +SlideShow.PlaybackBehavior.StopRestart="עצור כאשר אינו נראה, התחל מחדש כאשר נראה" SlideShow.PlaybackBehavior.PauseUnpause="השהה כאשר אינו נראה, בטל השהייה כאשר נראה" +SlideShow.PlaybackBehavior.AlwaysPlay="נגן תמיד גם כאשר לא נראה" SlideShow.SlideMode="מצב שקופית" SlideShow.SlideMode.Auto="אוטומטי" SlideShow.SlideMode.Manual="ידני (שימוש במקשים חמים לשליטה בהצגת השקופיות)" diff --git a/plugins/image-source/data/locale/kab-KAB.ini b/plugins/image-source/data/locale/kab-KAB.ini new file mode 100644 index 0000000..405269f --- /dev/null +++ b/plugins/image-source/data/locale/kab-KAB.ini @@ -0,0 +1,36 @@ +ImageInput="Tugna" +File="Afaylu n tugna" +UnloadWhenNotShowing="Sefsex tugna ticki ur tettwabeqqeḍ ara" + +SlideShow="Askan n tmaccagin n tugna" +SlideShow.TransitionSpeed="Arured n usaka (militasint)" +SlideShow.SlideTime="Akud gar tmaccagin(militasint)" +SlideShow.Files="Ifuyla n tugna" +SlideShow.CustomSize="Tiddi n ugrar/Assaɣ n tmeẓri" +SlideShow.CustomSize.Auto="Awurman" +SlideShow.Randomize="Taɣuri tagacurant" +SlideShow.Loop="Tineddict" +SlideShow.Transition="Asaka" +SlideShow.Transition.Cut="Gzem" +SlideShow.Transition.Fade="Tifsit" +SlideShow.Transition.Swipe="Seḥluceg" +SlideShow.Transition.Slide="Tamaccagt" +SlideShow.PlaybackBehavior="Tikli n twalit" +SlideShow.PlaybackBehavior.StopRestart="Ḥbes ticki ur yettban ara, ales asekker ticki yettban" +SlideShow.PlaybackBehavior.PauseUnpause="Bedd ticki ur yettban ara, kemmel ticki yettban" +SlideShow.PlaybackBehavior.AlwaysPlay="Ad itteddu yalas ɣas ma ur yettban ara" +SlideShow.SlideMode="Askar n tmaccagt" +SlideShow.SlideMode.Auto="Awurman" +SlideShow.SlideMode.Manual="Awfusan (Seqdec inegzumen n unasiw akken ad tsenqdeḍ askan n tmaccagin)" +SlideShow.PlayPause="Ɣer/Bedd" +SlideShow.Restart="Ales asekker" +SlideShow.Stop="Seḥbes" +SlideShow.NextSlide="Tamaccagt tuḍfirt" +SlideShow.PreviousSlide="Tamaccagt tuzwirt" +SlideShow.HideWhenDone="Ffer mi ara ifak uskan n tmaccagin" + +ColorSource="Aɣbalu n yini" +ColorSource.Color="Ini" +ColorSource.Width="Tehri" +ColorSource.Height="Tattayt" + diff --git a/plugins/image-source/data/locale/pt-BR.ini b/plugins/image-source/data/locale/pt-BR.ini index f84e17e..b898732 100644 --- a/plugins/image-source/data/locale/pt-BR.ini +++ b/plugins/image-source/data/locale/pt-BR.ini @@ -1,12 +1,12 @@ ImageInput="Imagem" -File="Arquivo de Imagem" +File="Arquivo de imagem" UnloadWhenNotShowing="Descarregar imagem quando não estiver em exibição" -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.CustomSize="Tamanho Delimitador/Proporção" +SlideShow="Apresentação de imagens" +SlideShow.TransitionSpeed="Velocidade da transição (em milissegundos)" +SlideShow.SlideTime="Tempo entre cada slide (em milissegundos)" +SlideShow.Files="Arquivos de imagem" +SlideShow.CustomSize="Tamanho da tela e proporção" SlideShow.CustomSize.Auto="Automático" SlideShow.Randomize="Reprodução aleatória" SlideShow.Loop="Loop" @@ -15,21 +15,21 @@ SlideShow.Transition.Cut="Corte" SlideShow.Transition.Fade="Esmaecer" SlideShow.Transition.Swipe="Arrastar" SlideShow.Transition.Slide="Deslizar" -SlideShow.PlaybackBehavior="Comportamento de Visibilidade" +SlideShow.PlaybackBehavior="Comportamento de visibilidade" SlideShow.PlaybackBehavior.StopRestart="Parar quando não visível, reiniciar quando visível" SlideShow.PlaybackBehavior.PauseUnpause="Pausa quando não visível, resumir quando visível" SlideShow.PlaybackBehavior.AlwaysPlay="Sempre reproduzir, mesmo quando não visível" SlideShow.SlideMode="Modo de slide" SlideShow.SlideMode.Auto="Automático" -SlideShow.SlideMode.Manual="Manual (Usar as teclas de atalho para controlar a apresentação)" +SlideShow.SlideMode.Manual="Manual (usar as teclas de atalho para controlar a apresentação)" SlideShow.PlayPause="Reproduzir/Pausar" SlideShow.Restart="Reiniciar" SlideShow.Stop="Parar" -SlideShow.NextSlide="Próximo Slide" -SlideShow.PreviousSlide="Slide Anterior" +SlideShow.NextSlide="Próximo slide" +SlideShow.PreviousSlide="Slide anterior" SlideShow.HideWhenDone="Esconder quando terminar a apresentação" -ColorSource="Fonte de Cor" +ColorSource="Fonte de cor" ColorSource.Color="Cor" ColorSource.Width="Largura" ColorSource.Height="Altura" diff --git a/plugins/image-source/data/locale/pt-PT.ini b/plugins/image-source/data/locale/pt-PT.ini index 8e1f5c5..cdf9262 100644 --- a/plugins/image-source/data/locale/pt-PT.ini +++ b/plugins/image-source/data/locale/pt-PT.ini @@ -6,6 +6,7 @@ SlideShow="Imagens em Deslize" SlideShow.TransitionSpeed="Velocidade de transição (milissegundos)" SlideShow.SlideTime="Tempo entre Deslizes (milissegundos)" SlideShow.Files="Arquivos de Imagem" +SlideShow.CustomSize="Tamanho do ecrã e proporção" SlideShow.CustomSize.Auto="Automático" SlideShow.Randomize="Reprodução aleatória" SlideShow.Loop="Loop" @@ -14,15 +15,21 @@ SlideShow.Transition.Cut="Cortar" SlideShow.Transition.Fade="Desvanecer" SlideShow.Transition.Swipe="Deslizar" SlideShow.Transition.Slide="Deslize" +SlideShow.PlaybackBehavior="Comportamento de visibilidade" +SlideShow.PlaybackBehavior.StopRestart="Parar quando não está visível, reiniciar quando está visível" +SlideShow.PlaybackBehavior.PauseUnpause="Pausar quando não está visível, retomar quando está visível" SlideShow.PlaybackBehavior.AlwaysPlay="Reproduzir sempre, mesmo quando não está visível" SlideShow.SlideMode="Modo de Slide" SlideShow.SlideMode.Auto="Automático" +SlideShow.SlideMode.Manual="Manual (usar as teclas para controlar a apresentação)" SlideShow.PlayPause="Play/Pausa" SlideShow.Restart="Reiniciar" SlideShow.Stop="Stop" SlideShow.NextSlide="Próximo Slide" SlideShow.PreviousSlide="Slide Anterior" +SlideShow.HideWhenDone="Ocultar quando a apresentação terminar" +ColorSource="Origem de cor" ColorSource.Color="Cor" ColorSource.Width="Largura" ColorSource.Height="Altura" diff --git a/plugins/image-source/data/locale/ro-RO.ini b/plugins/image-source/data/locale/ro-RO.ini index da5375c..ae26d63 100644 --- a/plugins/image-source/data/locale/ro-RO.ini +++ b/plugins/image-source/data/locale/ro-RO.ini @@ -6,9 +6,9 @@ SlideShow="Diaporamă" SlideShow.TransitionSpeed="Viteză de tranziție (milisecunde)" SlideShow.SlideTime="Timp între diapozitive (milisecunde)" SlideShow.Files="Fișiere de imagini" -SlideShow.CustomSize="Dimensiunea delimitării/Raport de aspect" -SlideShow.CustomSize.Auto="Automat" -SlideShow.Randomize="Randomizează redarea" +SlideShow.CustomSize="Dimensiunea încadrării/Raport de aspect" +SlideShow.CustomSize.Auto="Automat(ă)" +SlideShow.Randomize="Pune redarea într-o ordine aleatoare" SlideShow.Loop="Redă în buclă" SlideShow.Transition="Tranziție" SlideShow.Transition.Cut="Decupare" @@ -17,7 +17,7 @@ SlideShow.Transition.Swipe="Glisare" SlideShow.Transition.Slide="Culisare" SlideShow.PlaybackBehavior="Comportamentul vizibilității" SlideShow.PlaybackBehavior.StopRestart="Oprește când sursa nu este vizibilă, repornește când este vizibilă" -SlideShow.PlaybackBehavior.PauseUnpause="Pune pe pauză când sursa nu este vizibilă, scoate de pe pauză când este vizibilă" +SlideShow.PlaybackBehavior.PauseUnpause="Pune pe pauză când sursa nu e vizibilă, scoate de pe pauză când e vizibilă" SlideShow.PlaybackBehavior.AlwaysPlay="Redă întotdeauna chiar și atunci când sursa nu este vizibilă" SlideShow.SlideMode="Mod de culisare" SlideShow.SlideMode.Auto="Automat" @@ -27,7 +27,7 @@ SlideShow.Restart="Repornește" SlideShow.Stop="Oprește" SlideShow.NextSlide="Diapozitivul următor" SlideShow.PreviousSlide="Diapozitivul anterior" -SlideShow.HideWhenDone="Ascunde când slideshow este terminat" +SlideShow.HideWhenDone="Ascunde când diaporama este terminată" ColorSource="Sursă de culoare" ColorSource.Color="Culoare" diff --git a/plugins/linux-alsa/alsa-input.c b/plugins/linux-alsa/alsa-input.c index 568a746..6a113b0 100644 --- a/plugins/linux-alsa/alsa-input.c +++ b/plugins/linux-alsa/alsa-input.c @@ -440,9 +440,27 @@ bool _alsa_configure(struct alsa_data *data) return false; } - data->format = SND_PCM_FORMAT_S16; - err = snd_pcm_hw_params_set_format(data->handle, hwparams, - data->format); +#define FORMAT_SIZE 4 + snd_pcm_format_t formats[FORMAT_SIZE] = {SND_PCM_FORMAT_S16_LE, + SND_PCM_FORMAT_S32_LE, + SND_PCM_FORMAT_FLOAT_LE, + SND_PCM_FORMAT_U8}; + bool format_found = false; + for (int i = 0; i < FORMAT_SIZE; ++i) { + data->format = formats[i]; + err = snd_pcm_hw_params_test_format(data->handle, hwparams, + data->format); + if (err == 0) { + format_found = true; + break; + } + } +#undef FORMAT_SIZE + if (!format_found) { + blog(LOG_ERROR, "device doesnt support any OBS formats"); + return false; + } + snd_pcm_hw_params_set_format(data->handle, hwparams, data->format); if (err < 0) { blog(LOG_ERROR, "snd_pcm_hw_params_set_format failed: %s", snd_strerror(err)); diff --git a/plugins/linux-alsa/data/locale/az-AZ.ini b/plugins/linux-alsa/data/locale/az-AZ.ini new file mode 100644 index 0000000..a83fa9a --- /dev/null +++ b/plugins/linux-alsa/data/locale/az-AZ.ini @@ -0,0 +1,3 @@ +AlsaInput="Səs Yaxalama Cihazı (ALSA)" +Device="Cihaz" + diff --git a/plugins/linux-alsa/data/locale/kab-KAB.ini b/plugins/linux-alsa/data/locale/kab-KAB.ini new file mode 100644 index 0000000..74d8170 --- /dev/null +++ b/plugins/linux-alsa/data/locale/kab-KAB.ini @@ -0,0 +1,3 @@ +AlsaInput="Ibenk n tuṭṭfa n umeslaw (ALSA)" +Device="Ibenk" + diff --git a/plugins/linux-alsa/data/locale/pt-BR.ini b/plugins/linux-alsa/data/locale/pt-BR.ini index 2eef7ca..d272f9b 100644 --- a/plugins/linux-alsa/data/locale/pt-BR.ini +++ b/plugins/linux-alsa/data/locale/pt-BR.ini @@ -1,3 +1,3 @@ -AlsaInput="Dispositivo de Captura de Áudio (ALSA)" +AlsaInput="Dispositivo de captura de áudio (ALSA)" Device="Dispositivo" diff --git a/plugins/linux-capture/data/locale/az-AZ.ini b/plugins/linux-capture/data/locale/az-AZ.ini index b2b1138..794d184 100644 --- a/plugins/linux-capture/data/locale/az-AZ.ini +++ b/plugins/linux-capture/data/locale/az-AZ.ini @@ -1,2 +1,16 @@ +X11SharedMemoryScreenInput="Ekran Yaxalama (XSHM)" +Screen="Ekran" +CaptureCursor="Kursoru Yaxala" +AdvancedSettings="Qabaqcıl Tənzimləmələr" XServer="X Server" +XCCapture="Pəncərə Yaxalama (Xcomposite)" +Window="Pəncərə" +CropTop="Üstdən Götür (piksel)" +CropLeft="Soldan Götür (piksel)" +CropRight="Sağdan Götür (piksel)" +CropBottom="Altdan Götür (piksel)" +SwapRedBlue="Qırmızı və mavini dəyişdir" +LockX="Yaxalama vaxtı X serveri kilidlə" +IncludeXBorder="X Çərçivəsini daxil et" +ExcludeAlpha="Alfa olmana toxuma formatından istifadə edin (Mesa müvəqqəti həll)" diff --git a/plugins/linux-capture/data/locale/de-DE.ini b/plugins/linux-capture/data/locale/de-DE.ini index f3870d6..e72024c 100644 --- a/plugins/linux-capture/data/locale/de-DE.ini +++ b/plugins/linux-capture/data/locale/de-DE.ini @@ -2,7 +2,7 @@ X11SharedMemoryScreenInput="Bildschirmaufnahme (XSHM)" Screen="Bildschirm" CaptureCursor="Mauszeiger aufnehmen" AdvancedSettings="Erweiterte Einstellungen" -XServer="X‐Server" +XServer="X-Server" XCCapture="Fensteraufnahme (Xcomposite)" Window="Fenster" CropTop="Oben abschneiden (Pixel)" @@ -10,7 +10,7 @@ CropLeft="Links abschneiden (Pixel)" CropRight="Rechts abschneiden (Pixel)" CropBottom="Unten abschneiden (Pixel)" SwapRedBlue="Rot und Blau tauschen" -LockX="X‐Server während der Aufnahme sperren" -IncludeXBorder="X‐Rahmen anzeigen" -ExcludeAlpha="Alphaloses Texturformat verwenden (Mesa‐Problemumgehung)" +LockX="X-Server während der Aufnahme sperren" +IncludeXBorder="X-Rahmen anzeigen" +ExcludeAlpha="Alphaloses Texturformat verwenden (Mesa-Problemumgehung)" diff --git a/plugins/linux-capture/data/locale/kab-KAB.ini b/plugins/linux-capture/data/locale/kab-KAB.ini new file mode 100644 index 0000000..dfae060 --- /dev/null +++ b/plugins/linux-capture/data/locale/kab-KAB.ini @@ -0,0 +1,16 @@ +X11SharedMemoryScreenInput="Tuṭṭfa n ugdil (XSHM)" +Screen="Agdil" +CaptureCursor="Ṭṭef taḥnaccaḍt" +AdvancedSettings="Iɣewwaren inaẓiyen" +XServer="Aqeddac X" +XCCapture="Ṭṭef asfaylu (Xcomposite)" +Window="Asfaylu" +CropTop="Ɣeẓ uksawen (ipikslen)" +CropLeft="Ɣeẓ deg uzelmaḍ (ipikslen)" +CropRight="Ɣeẓ deg uyfus (ipikslen)" +CropBottom="Ɣeẓ ukessar (ipikslen)" +SwapRedBlue="Semsekkel azeggaɣ akked unili" +LockX="Sekkeṛ aqeddac X di tuṭṭfa" +IncludeXBorder="Seddu iri X" +ExcludeAlpha="Seqdec amasal n tizḍi war alfa (amselsu i Mesa)" + diff --git a/plugins/linux-capture/data/locale/pt-BR.ini b/plugins/linux-capture/data/locale/pt-BR.ini index 567edfa..ac92f21 100644 --- a/plugins/linux-capture/data/locale/pt-BR.ini +++ b/plugins/linux-capture/data/locale/pt-BR.ini @@ -1,9 +1,9 @@ X11SharedMemoryScreenInput="Captura de Tela (XSHM)" Screen="Tela" -CaptureCursor="Capturar o Cursor" +CaptureCursor="Capturar o cursor" AdvancedSettings="Configurações Avançadas" XServer="Servidor x" -XCCapture="Captura de Janela (Xcomposite)" +XCCapture="Captura de janela (Xcomposite)" Window="Janela" CropTop="Cortar em Cima (Pixels)" CropLeft="Cortar à Esquerda (Pixels)" diff --git a/plugins/linux-jack/data/locale/az-AZ.ini b/plugins/linux-jack/data/locale/az-AZ.ini new file mode 100644 index 0000000..a177929 --- /dev/null +++ b/plugins/linux-jack/data/locale/az-AZ.ini @@ -0,0 +1,4 @@ +StartJACKServer="JACK serveri başlat" +Channels="Kanal sayı" +JACKInput="JACK Giriş Müştərisi" + diff --git a/plugins/linux-jack/data/locale/de-DE.ini b/plugins/linux-jack/data/locale/de-DE.ini index 25c86ef..2c222bb 100644 --- a/plugins/linux-jack/data/locale/de-DE.ini +++ b/plugins/linux-jack/data/locale/de-DE.ini @@ -1,4 +1,4 @@ -StartJACKServer="JACK‐Server starten" +StartJACKServer="JACK-Server starten" Channels="Anzahl der Kanäle" -JACKInput="JACK‐Eingabe‐Client" +JACKInput="JACK-Eingabe-Client" diff --git a/plugins/linux-jack/data/locale/kab-KAB.ini b/plugins/linux-jack/data/locale/kab-KAB.ini new file mode 100644 index 0000000..fa1abb9 --- /dev/null +++ b/plugins/linux-jack/data/locale/kab-KAB.ini @@ -0,0 +1,4 @@ +StartJACKServer="Sekker aqeddac JACK" +Channels="Amḍan n ibuda" +JACKInput="Amsaɣ n unekcum n JACK" + diff --git a/plugins/linux-pulseaudio/data/locale/az-AZ.ini b/plugins/linux-pulseaudio/data/locale/az-AZ.ini new file mode 100644 index 0000000..a8bd8c1 --- /dev/null +++ b/plugins/linux-pulseaudio/data/locale/az-AZ.ini @@ -0,0 +1,4 @@ +PulseInput="Səs Giriş Yaxalama (PulseAudio)" +PulseOutput="Səs Çıxış Yaxalama (PulseAudio)" +Device="Cihaz" + diff --git a/plugins/linux-pulseaudio/data/locale/kab-KAB.ini b/plugins/linux-pulseaudio/data/locale/kab-KAB.ini new file mode 100644 index 0000000..83b9e70 --- /dev/null +++ b/plugins/linux-pulseaudio/data/locale/kab-KAB.ini @@ -0,0 +1,4 @@ +PulseInput="Tuṭṭfa n unekcum ameslaw (PulseAudio)" +PulseOutput="Tuṭṭfa n tuffɣa tmeslawt (PulseAudio)" +Device="Ibenk" + diff --git a/plugins/linux-v4l2/CMakeLists.txt b/plugins/linux-v4l2/CMakeLists.txt index 89882cc..51047ec 100644 --- a/plugins/linux-v4l2/CMakeLists.txt +++ b/plugins/linux-v4l2/CMakeLists.txt @@ -39,6 +39,7 @@ set(linux-v4l2_SOURCES v4l2-controls.c v4l2-input.c v4l2-helpers.c + v4l2-output.c ${linux-v4l2-udev_SOURCES} ) diff --git a/plugins/linux-v4l2/data/locale/az-AZ.ini b/plugins/linux-v4l2/data/locale/az-AZ.ini new file mode 100644 index 0000000..daefb34 --- /dev/null +++ b/plugins/linux-v4l2/data/locale/az-AZ.ini @@ -0,0 +1,16 @@ +V4L2Input="Video Yaxalama Cihazı (V4L2)" +Device="Cihaz" +Input="Giriş" +VideoFormat="Video formatı" +VideoStandard="Video standartı" +DVTiming="DV zamanlama" +Resolution="Ölçülər" +FrameRate="Kadr sürəti" +LeaveUnchanged="Dəyişmədən çıx" +UseBuffering="Bufferləməni istifadə et" +ColorRange="Rəng aralığı" +ColorRange.Default="İlkin" +ColorRange.Partial="Hissəli" +ColorRange.Full="Tam" +CameraCtrls="Kamera nəzarəti" + diff --git a/plugins/linux-v4l2/data/locale/de-DE.ini b/plugins/linux-v4l2/data/locale/de-DE.ini index 4d42992..71b21bb 100644 --- a/plugins/linux-v4l2/data/locale/de-DE.ini +++ b/plugins/linux-v4l2/data/locale/de-DE.ini @@ -3,7 +3,7 @@ Device="Gerät" Input="Eingabe" VideoFormat="Videoformat" VideoStandard="Videostandard" -DVTiming="DV‐Timing" +DVTiming="DV-Timing" Resolution="Auflösung" FrameRate="Bildrate" LeaveUnchanged="Unverändert lassen" diff --git a/plugins/linux-v4l2/data/locale/el-GR.ini b/plugins/linux-v4l2/data/locale/el-GR.ini index b90e717..eff208b 100644 --- a/plugins/linux-v4l2/data/locale/el-GR.ini +++ b/plugins/linux-v4l2/data/locale/el-GR.ini @@ -8,4 +8,9 @@ Resolution="Ανάλυση" FrameRate="Ρυθμός καρέ" LeaveUnchanged="Αφήστε αμετάβλητο" UseBuffering="Χρήση ενδιάμεσης μνήμης" +ColorRange="Εύρος Χρωμάτων" +ColorRange.Default="Προεπιλογή" +ColorRange.Partial="Μερικό" +ColorRange.Full="Πλήρες" +CameraCtrls="Έλεγχοι φωτογραφικής μηχανής" diff --git a/plugins/linux-v4l2/data/locale/et-EE.ini b/plugins/linux-v4l2/data/locale/et-EE.ini index 82f570d..eb362f1 100644 --- a/plugins/linux-v4l2/data/locale/et-EE.ini +++ b/plugins/linux-v4l2/data/locale/et-EE.ini @@ -8,4 +8,9 @@ Resolution="Resolutsioon" FrameRate="Kaadrisagedus" LeaveUnchanged="Jäta muutmata" UseBuffering="Kasuta puhverdamist" +ColorRange="Värviruumi vahemik" +ColorRange.Default="Vaikeseade" +ColorRange.Partial="Osaline" +ColorRange.Full="Täielik" +CameraCtrls="Kaamera juhtnupud" diff --git a/plugins/linux-v4l2/data/locale/fa-IR.ini b/plugins/linux-v4l2/data/locale/fa-IR.ini index 95ac133..988ade8 100644 --- a/plugins/linux-v4l2/data/locale/fa-IR.ini +++ b/plugins/linux-v4l2/data/locale/fa-IR.ini @@ -12,4 +12,5 @@ ColorRange="محدوده رنگ" ColorRange.Default="پیش فرض" ColorRange.Partial="جزئی" ColorRange.Full="کامل" +CameraCtrls="کنترل دوربین" diff --git a/plugins/linux-v4l2/data/locale/kab-KAB.ini b/plugins/linux-v4l2/data/locale/kab-KAB.ini new file mode 100644 index 0000000..3f39193 --- /dev/null +++ b/plugins/linux-v4l2/data/locale/kab-KAB.ini @@ -0,0 +1,16 @@ +V4L2Input="Ibenk n tuṭṭfa n uvidyu (V4L2)" +Device="Ibenk" +Input="Anekcum" +VideoFormat="Amasal n uvidyu" +VideoStandard="Alugen n uvidyu" +DVTiming="Akud DV" +Resolution="Tabadut" +FrameRate="Atug n yikataren" +LeaveUnchanged="Eǧǧ-it s war abeddel" +UseBuffering="Seqdec ajmaɛ di tkatut n weḥraz" +ColorRange="Tagrumma n yini" +ColorRange.Default="Amezwar" +ColorRange.Partial="Abruyan" +ColorRange.Full="Ummid" +CameraCtrls="Isenqaden n tkamiṛat" + diff --git a/plugins/linux-v4l2/data/locale/pt-BR.ini b/plugins/linux-v4l2/data/locale/pt-BR.ini index ae5e7ea..6a5c330 100644 --- a/plugins/linux-v4l2/data/locale/pt-BR.ini +++ b/plugins/linux-v4l2/data/locale/pt-BR.ini @@ -1,7 +1,7 @@ -V4L2Input="Dispositivo de Captura de Vídeo (V4L2)" +V4L2Input="Dispositivo de captura de vídeo (V4L2)" Device="Dispositivo" Input="Entrada" -VideoFormat="Formato de Vídeo" +VideoFormat="Formato de vídeo" VideoStandard="Padrão de vídeo" DVTiming="Sincronismo DV" Resolution="Resolução" diff --git a/plugins/linux-v4l2/data/locale/ro-RO.ini b/plugins/linux-v4l2/data/locale/ro-RO.ini index c835c91..b374500 100644 --- a/plugins/linux-v4l2/data/locale/ro-RO.ini +++ b/plugins/linux-v4l2/data/locale/ro-RO.ini @@ -12,5 +12,5 @@ ColorRange="Gamă de culori" ColorRange.Default="Implicită" ColorRange.Partial="Parțială" ColorRange.Full="Completă" -CameraCtrls="Controale cameră foto" +CameraCtrls="Comenzi pentru cameră" diff --git a/plugins/linux-v4l2/data/locale/vi-VN.ini b/plugins/linux-v4l2/data/locale/vi-VN.ini index 33a0690..638485b 100644 --- a/plugins/linux-v4l2/data/locale/vi-VN.ini +++ b/plugins/linux-v4l2/data/locale/vi-VN.ini @@ -1,7 +1,15 @@ +V4L2Input="Thiết bị quay video (V4L2)" Device="Thiết bị" +Input="Đầu vào" +VideoFormat="Định dạng video" VideoStandard="Video Tiêu chuẩn" Resolution="Độ phân giải" FrameRate="Tốc độ khung" LeaveUnchanged="Giữ nguyên" +UseBuffering="Dùng đệm" +ColorRange="Dải màu" +ColorRange.Default="Mặc định" +ColorRange.Partial="Một phần" +ColorRange.Full="Toàn phần" CameraCtrls="Điều khiển máy quay" diff --git a/plugins/linux-v4l2/linux-v4l2.c b/plugins/linux-v4l2/linux-v4l2.c index b57deaa..0df5445 100644 --- a/plugins/linux-v4l2/linux-v4l2.c +++ b/plugins/linux-v4l2/linux-v4l2.c @@ -15,18 +15,47 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include +#include OBS_DECLARE_MODULE() OBS_MODULE_USE_DEFAULT_LOCALE("linux-v4l2", "en-US") MODULE_EXPORT const char *obs_module_description(void) { - return "Video4Linux2(V4L2) sources"; + return "Video4Linux2(V4L2) sources/virtual camera"; } extern struct obs_source_info v4l2_input; +extern struct obs_output_info virtualcam_info; + +static bool v4l2loopback_installed() +{ + bool loaded = false; + + int ret = system("modinfo v4l2loopback >/dev/null 2>&1"); + + if (ret == 0) + loaded = true; + + return loaded; +} bool obs_module_load(void) { obs_register_source(&v4l2_input); + + obs_data_t *obs_settings = obs_data_create(); + + if (v4l2loopback_installed()) { + obs_register_output(&virtualcam_info); + obs_data_set_bool(obs_settings, "vcamEnabled", true); + } else { + obs_data_set_bool(obs_settings, "vcamEnabled", false); + blog(LOG_WARNING, + "v4l2loopback not installed, virtual camera disabled"); + } + + obs_apply_private_data(obs_settings); + obs_data_release(obs_settings); + return true; } diff --git a/plugins/linux-v4l2/v4l2-output.c b/plugins/linux-v4l2/v4l2-output.c new file mode 100644 index 0000000..ab560cb --- /dev/null +++ b/plugins/linux-v4l2/v4l2-output.c @@ -0,0 +1,176 @@ +#include +#include +#include +#include +#include +#include + +#define MAX_DEVICES 64 + +struct virtualcam_data { + obs_output_t *output; + int device; + uint32_t frame_size; +}; + +static const char *virtualcam_name(void *unused) +{ + UNUSED_PARAMETER(unused); + return "Virtual Camera Output"; +} + +static void virtualcam_destroy(void *data) +{ + struct virtualcam_data *vcam = (struct virtualcam_data *)data; + close(vcam->device); + bfree(data); +} + +static bool loopback_module_loaded() +{ + bool loaded = false; + + char temp[512]; + + FILE *fp = fopen("/proc/modules", "r"); + + if (!fp) + return false; + + while (fgets(temp, sizeof(temp), fp)) { + if (strstr(temp, "v4l2loopback")) { + loaded = true; + break; + } + } + + if (fp) + fclose(fp); + + return loaded; +} + +static int loopback_module_load() +{ + return system( + "pkexec modprobe v4l2loopback exclusive_caps=1 card_label='OBS Virtual Camera' && sleep 0.5"); +} + +static void *virtualcam_create(obs_data_t *settings, obs_output_t *output) +{ + struct virtualcam_data *vcam = + (struct virtualcam_data *)bzalloc(sizeof(*vcam)); + vcam->output = output; + + UNUSED_PARAMETER(settings); + return vcam; +} + +static bool try_connect(void *data, int device) +{ + struct virtualcam_data *vcam = (struct virtualcam_data *)data; + struct v4l2_format format; + struct v4l2_capability capability; + struct v4l2_streamparm parm; + + uint32_t width = obs_output_get_width(vcam->output); + uint32_t height = obs_output_get_height(vcam->output); + + vcam->frame_size = width * height * 2; + + char new_device[16]; + sprintf(new_device, "/dev/video%d", device); + + vcam->device = open(new_device, O_RDWR); + + if (vcam->device < 0) + return false; + + if (ioctl(vcam->device, VIDIOC_QUERYCAP, &capability) < 0) + return false; + + format.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; + + if (ioctl(vcam->device, VIDIOC_G_FMT, &format) < 0) + return false; + + struct obs_video_info ovi; + obs_get_video_info(&ovi); + + memset(&parm, 0, sizeof(parm)); + parm.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; + + parm.parm.output.capability = V4L2_CAP_TIMEPERFRAME; + parm.parm.output.timeperframe.numerator = ovi.fps_den; + parm.parm.output.timeperframe.denominator = ovi.fps_num; + + if (ioctl(vcam->device, VIDIOC_S_PARM, &parm) < 0) + return false; + + format.fmt.pix.width = width; + format.fmt.pix.height = height; + format.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV; + format.fmt.pix.sizeimage = vcam->frame_size; + + if (ioctl(vcam->device, VIDIOC_S_FMT, &format) < 0) + return false; + + struct video_scale_info vsi = {0}; + vsi.format = VIDEO_FORMAT_YUY2; + vsi.width = width; + vsi.height = height; + obs_output_set_video_conversion(vcam->output, &vsi); + + blog(LOG_INFO, "Virtual camera started"); + obs_output_begin_data_capture(vcam->output, 0); + + return true; +} + +static bool virtualcam_start(void *data) +{ + struct virtualcam_data *vcam = (struct virtualcam_data *)data; + + if (!loopback_module_loaded()) { + if (loopback_module_load() != 0) + return false; + } + + for (int i = 0; i < MAX_DEVICES; i++) { + if (!try_connect(vcam, i)) + continue; + else + return true; + } + + blog(LOG_WARNING, "Failed to start virtual camera"); + return false; +} + +static void virtualcam_stop(void *data, uint64_t ts) +{ + struct virtualcam_data *vcam = (struct virtualcam_data *)data; + obs_output_end_data_capture(vcam->output); + close(vcam->device); + + blog(LOG_INFO, "Virtual camera stopped"); + + UNUSED_PARAMETER(ts); +} + +static void virtual_video(void *param, struct video_data *frame) +{ + struct virtualcam_data *vcam = (struct virtualcam_data *)param; + write(vcam->device, frame->data[0], vcam->frame_size); +} + +struct obs_output_info virtualcam_info = { + .id = "virtualcam_output", + .flags = OBS_OUTPUT_VIDEO, + .get_name = virtualcam_name, + .create = virtualcam_create, + .destroy = virtualcam_destroy, + .start = virtualcam_start, + .stop = virtualcam_stop, + .raw_video = virtual_video, +}; diff --git a/plugins/mac-avcapture/data/locale/az-AZ.ini b/plugins/mac-avcapture/data/locale/az-AZ.ini new file mode 100644 index 0000000..89a6bb5 --- /dev/null +++ b/plugins/mac-avcapture/data/locale/az-AZ.ini @@ -0,0 +1,14 @@ +AVCapture="Video Yaxalama Cihazı" +Device="Cihaz" +UsePreset="Hazır tənzimləməni istifadə et" +Preset="Hazır tənzimləmə" +Buffering="Bufferləməni istifadə et" +FrameRate="Kadr sürəti" +InputFormat="Giriş formatı" +ColorSpace="Rəng boşluğu" +VideoRange="Video aralığı" +VideoRange.Partial="Hissəli" +VideoRange.Full="Tam" +Auto="Avtomatik" +Unknown="Bilinmir ($1)" + diff --git a/plugins/mac-avcapture/data/locale/kab-KAB.ini b/plugins/mac-avcapture/data/locale/kab-KAB.ini new file mode 100644 index 0000000..7ce29c4 --- /dev/null +++ b/plugins/mac-avcapture/data/locale/kab-KAB.ini @@ -0,0 +1,14 @@ +AVCapture="Ibenk n tuṭṭfa n uvidyu" +Device="Ibenk" +UsePreset="Seqdec aɣewwar uzwir" +Preset="Aseɣwer uzwir" +Buffering="Seqdec ajmaɛ di tkatut n weḥraz" +FrameRate="Atug n yikataren" +InputFormat="Amasal n unekcum" +ColorSpace="Tallunt n yini" +VideoRange="Tagrumma n uvidyu" +VideoRange.Partial="Abruyan" +VideoRange.Full="Ummid" +Auto="Awurman" +Unknown="Arussin ($1)" + diff --git a/plugins/mac-avcapture/data/locale/pt-BR.ini b/plugins/mac-avcapture/data/locale/pt-BR.ini index 2966cfb..da9957a 100644 --- a/plugins/mac-avcapture/data/locale/pt-BR.ini +++ b/plugins/mac-avcapture/data/locale/pt-BR.ini @@ -1,4 +1,4 @@ -AVCapture="Dispositivo de Captura de Vídeo" +AVCapture="Dispositivo de captura de vídeo" Device="Dispositivo" UsePreset="Usar Predefinição" Preset="Predefinição" diff --git a/plugins/mac-avcapture/data/locale/pt-PT.ini b/plugins/mac-avcapture/data/locale/pt-PT.ini index 262f16a..093cc82 100644 --- a/plugins/mac-avcapture/data/locale/pt-PT.ini +++ b/plugins/mac-avcapture/data/locale/pt-PT.ini @@ -6,6 +6,7 @@ Buffering="Utilizar Buffering" FrameRate="Taxa de frames (frame rate)" InputFormat="Formato de entrada" ColorSpace="Espaço de cor" +VideoRange="Intervalo de vídeo" VideoRange.Partial="Parcial" VideoRange.Full="Completo" Auto="Auto" diff --git a/plugins/mac-avcapture/data/locale/vi-VN.ini b/plugins/mac-avcapture/data/locale/vi-VN.ini index a52a172..00272d6 100644 --- a/plugins/mac-avcapture/data/locale/vi-VN.ini +++ b/plugins/mac-avcapture/data/locale/vi-VN.ini @@ -1,5 +1,12 @@ +AVCapture="Thiết bị ghi hình" Device="Thiết bị" UsePreset="Dùng mẫu có sẵn" +Preset="Mẫu thiết lập" +Buffering="Dùng đệm" +FrameRate="Tốc độ khung hình" +InputFormat="Định dạng đầu vào" +VideoRange.Partial="Một phần" +VideoRange.Full="Đầy đủ" Auto="Tự động" Unknown="Không xác định ($1)" diff --git a/plugins/mac-capture/CMakeLists.txt b/plugins/mac-capture/CMakeLists.txt index 66f1a18..851f9f1 100644 --- a/plugins/mac-capture/CMakeLists.txt +++ b/plugins/mac-capture/CMakeLists.txt @@ -24,11 +24,6 @@ set(mac-capture_SOURCES mac-window-capture.m window-utils.m) -set_source_files_properties(mac-display-capture.m - mac-window-capture.m - window-utils.m - PROPERTIES LANGUAGE C) - add_library(mac-capture MODULE ${mac-capture_SOURCES} ${mac-capture_HEADERS}) diff --git a/plugins/mac-capture/data/locale/az-AZ.ini b/plugins/mac-capture/data/locale/az-AZ.ini index 4c6b5d5..b5dc634 100644 --- a/plugins/mac-capture/data/locale/az-AZ.ini +++ b/plugins/mac-capture/data/locale/az-AZ.ini @@ -1,2 +1,21 @@ +CoreAudio.InputCapture="Səs Giriş Yaxalama" +CoreAudio.OutputCapture="Səs Çıxış Yaxalama" +CoreAudio.Device="Cihaz" +CoreAudio.Device.Default="İlkin" +DisplayCapture="Ekran Yaxalama" +DisplayCapture.Display="Ekran" +DisplayCapture.ShowCursor="Kursoru göstər" +WindowCapture="Pəncərə Yaxalama" +WindowCapture.ShowShadow="Pəncərə kölgəsini göstər" +WindowUtils.Window="Pəncərə" +WindowUtils.ShowEmptyNames="Adsız pəncərələri göstər" +CropMode="Götür" CropMode.None="Heç biri" +CropMode.Manual="Əllə" +CropMode.ToWindow="Pəncərəyə" +CropMode.ToWindowAndManual="Pəncərəyə və əllə" +Crop.origin.x="Soldan götür" +Crop.origin.y="Üstdən götür" +Crop.size.width="Sağdan götür" +Crop.size.height="Altdan götür" diff --git a/plugins/mac-capture/data/locale/kab-KAB.ini b/plugins/mac-capture/data/locale/kab-KAB.ini new file mode 100644 index 0000000..c2ce83e --- /dev/null +++ b/plugins/mac-capture/data/locale/kab-KAB.ini @@ -0,0 +1,21 @@ +CoreAudio.InputCapture="Tuṭṭfa n unekcum n umeslaw" +CoreAudio.OutputCapture="Tuṭṭfa n tuffɣa n umeslaw" +CoreAudio.Device="Ibenk" +CoreAudio.Device.Default="Amezwar" +DisplayCapture="Tuṭṭfa n ubeqqeḍ" +DisplayCapture.Display="Beqqeḍ" +DisplayCapture.ShowCursor="Beqqeḍ taḥnaccaḍt" +WindowCapture="Tuṭṭfa n usfaylu" +WindowCapture.ShowShadow="Beqqeḍ tili n usfaylu" +WindowUtils.Window="Asfaylu" +WindowUtils.ShowEmptyNames="Beqqeḍ isfuyla ur nesɛi ara isem" +CropMode="Ɣeẓ" +CropMode.None="Ulac" +CropMode.Manual="S ufus" +CropMode.ToWindow="Ɣer usfaylu" +CropMode.ToWindowAndManual="Ɣer usfaylu yerna s ufus" +Crop.origin.x="Ɣeẓ seg uzelmaḍ" +Crop.origin.y="Ɣeẓ uksawen" +Crop.size.width="Ɣeẓ seg uyfus" +Crop.size.height="Ɣeẓ ukessar" + diff --git a/plugins/mac-capture/data/locale/pt-BR.ini b/plugins/mac-capture/data/locale/pt-BR.ini index b08eba1..2848ae6 100644 --- a/plugins/mac-capture/data/locale/pt-BR.ini +++ b/plugins/mac-capture/data/locale/pt-BR.ini @@ -1,12 +1,12 @@ -CoreAudio.InputCapture="Captura de Entrada de Áudio" -CoreAudio.OutputCapture="Captura de Saída de Áudio" +CoreAudio.InputCapture="Captura de entrada de áudio" +CoreAudio.OutputCapture="Captura de saída de áudio" CoreAudio.Device="Dispositivo" CoreAudio.Device.Default="Padrão" DisplayCapture="Captura de Exposição" DisplayCapture.Display="Exposição" -DisplayCapture.ShowCursor="Mostrar o Cursor" +DisplayCapture.ShowCursor="Mostrar o cursor" WindowCapture="Captura de janela" -WindowCapture.ShowShadow="Mostrar sombra da Janela" +WindowCapture.ShowShadow="Mostrar sombra da janela" WindowUtils.Window="Janela" WindowUtils.ShowEmptyNames="Mostrar janelas com nomes vazios" CropMode="Recortar" diff --git a/plugins/mac-capture/data/locale/vi-VN.ini b/plugins/mac-capture/data/locale/vi-VN.ini index 93664a8..377c3b4 100644 --- a/plugins/mac-capture/data/locale/vi-VN.ini +++ b/plugins/mac-capture/data/locale/vi-VN.ini @@ -6,11 +6,14 @@ DisplayCapture="Quay màn hình" DisplayCapture.Display="Hiển thị" DisplayCapture.ShowCursor="Hiển thị con trỏ" WindowCapture="Quay cửa sổ" +WindowCapture.ShowShadow="Hiện bóng của cửa sổ" WindowUtils.Window="Cửa sổ" WindowUtils.ShowEmptyNames="Hiện thị cửa sổ mà không có tên" CropMode="Cắt" CropMode.None="Không" CropMode.Manual="Thủ công" +CropMode.ToWindow="Tới cửa số" +CropMode.ToWindowAndManual="Tới cửa sổ và hướng dẫn" Crop.origin.x="Cắt trái" Crop.origin.y="Cắt trên" Crop.size.width="Cắt phải" diff --git a/plugins/mac-syphon/CMakeLists.txt b/plugins/mac-syphon/CMakeLists.txt index e203136..d8a3a5b 100644 --- a/plugins/mac-syphon/CMakeLists.txt +++ b/plugins/mac-syphon/CMakeLists.txt @@ -65,9 +65,6 @@ set(mac-syphon_SOURCES syphon.m plugin-main.c) -set_source_files_properties(${mac-syphon_SOURCES} ${syphon_SOURCES} - PROPERTIES LANGUAGE C) - add_definitions(-DSYPHON_UNIQUE_CLASS_NAME_PREFIX=OBS_ -include ${PROJECT_SOURCE_DIR}/syphon-framework/Syphon_Prefix.pch) diff --git a/plugins/mac-syphon/data/locale/az-AZ.ini b/plugins/mac-syphon/data/locale/az-AZ.ini new file mode 100644 index 0000000..7ef9bcf --- /dev/null +++ b/plugins/mac-syphon/data/locale/az-AZ.ini @@ -0,0 +1,13 @@ +Syphon="Syphon Müştərisi" +Source="Mənbə" +LaunchSyphonInject="SyphonInject-i başlat" +Inject="Yerit" +Application="Tətbiqetmə" +SyphonLicense="Syphon Lisenziyası" +Crop="Götür" +Crop.origin.x="Soldan götür" +Crop.origin.y="Üstdən götür" +Crop.size.width="Sağdan götür" +Crop.size.height="Altdan götür" +AllowTransparency="Şəffaflığa icazə ver" + diff --git a/plugins/mac-syphon/data/locale/de-DE.ini b/plugins/mac-syphon/data/locale/de-DE.ini index 3e03adb..eb3e43c 100644 --- a/plugins/mac-syphon/data/locale/de-DE.ini +++ b/plugins/mac-syphon/data/locale/de-DE.ini @@ -1,9 +1,9 @@ -Syphon="Syphon‐Client" +Syphon="Syphon-Client" Source="Quelle" LaunchSyphonInject="SyphonInject starten" Inject="Injizieren" Application="Anwendung" -SyphonLicense="Syphon‐Lizenz" +SyphonLicense="Syphon-Lizenz" Crop="Zuschneiden" Crop.origin.x="Links abschneiden" Crop.origin.y="Oben abschneiden" diff --git a/plugins/mac-syphon/data/locale/et-EE.ini b/plugins/mac-syphon/data/locale/et-EE.ini index 2718251..ca04f25 100644 --- a/plugins/mac-syphon/data/locale/et-EE.ini +++ b/plugins/mac-syphon/data/locale/et-EE.ini @@ -1,3 +1,4 @@ +Syphon="Klient Syphon" Source="Allikas" LaunchSyphonInject="Käivita SyphonInject" Inject="Sisesta" diff --git a/plugins/mac-syphon/data/locale/kab-KAB.ini b/plugins/mac-syphon/data/locale/kab-KAB.ini new file mode 100644 index 0000000..39043e6 --- /dev/null +++ b/plugins/mac-syphon/data/locale/kab-KAB.ini @@ -0,0 +1,13 @@ +Syphon="Amsaɣ Syphon" +Source="Aɣbalu" +LaunchSyphonInject="Sekker SyphonInject" +Inject="Sduffi" +Application="Asnas" +SyphonLicense="Turagt n Syphon" +Crop="Ɣeẓ" +Crop.origin.x="Ɣeẓ seg uzelmaḍ" +Crop.origin.y="Ɣeẓ uksawen" +Crop.size.width="Ɣeẓ seg uyfus" +Crop.size.height="Ɣeẓ ukessar" +AllowTransparency="Sireg tafrawant" + diff --git a/plugins/mac-syphon/data/locale/vi-VN.ini b/plugins/mac-syphon/data/locale/vi-VN.ini index e1e1b09..861bc83 100644 --- a/plugins/mac-syphon/data/locale/vi-VN.ini +++ b/plugins/mac-syphon/data/locale/vi-VN.ini @@ -1,5 +1,9 @@ +Syphon="Syphon Khách" Source="Nguồn" +LaunchSyphonInject="Chạy SyphonInject" +Inject="Chọn" Application="Ứng dụng" +SyphonLicense="Giấy phép Syphon" Crop="Cắt" Crop.origin.x="Cắt trái" Crop.origin.y="Cắt trên" diff --git a/plugins/mac-virtualcam/CMakeLists.txt b/plugins/mac-virtualcam/CMakeLists.txt new file mode 100644 index 0000000..843c0cb --- /dev/null +++ b/plugins/mac-virtualcam/CMakeLists.txt @@ -0,0 +1,2 @@ +add_subdirectory(src/obs-plugin) +add_subdirectory(src/dal-plugin) diff --git a/plugins/mac-virtualcam/data/locale/en-US.ini b/plugins/mac-virtualcam/data/locale/en-US.ini new file mode 100644 index 0000000..e69de29 diff --git a/plugins/mac-virtualcam/src/common/MachProtocol.h b/plugins/mac-virtualcam/src/common/MachProtocol.h new file mode 100644 index 0000000..54b8d25 --- /dev/null +++ b/plugins/mac-virtualcam/src/common/MachProtocol.h @@ -0,0 +1,17 @@ +// +// MachProtocol.m +// obs-mac-virtualcam +// +// Created by John Boiles on 5/5/20. +// + +#define MACH_SERVICE_NAME "com.obsproject.obs-mac-virtualcam.server" + +typedef enum { + //! Initial connect message sent from the client to the server to initate a connection + MachMsgIdConnect = 1, + //! Message containing data for a frame + MachMsgIdFrame = 2, + //! Indicates the server is going to stop sending frames + MachMsgIdStop = 3, +} MachMsgId; diff --git a/plugins/mac-virtualcam/src/dal-plugin/CMSampleBufferUtils.h b/plugins/mac-virtualcam/src/dal-plugin/CMSampleBufferUtils.h new file mode 100644 index 0000000..f0c659a --- /dev/null +++ b/plugins/mac-virtualcam/src/dal-plugin/CMSampleBufferUtils.h @@ -0,0 +1,22 @@ +// +// CMSampleBufferUtils.h +// dal-plugin +// +// Created by John Boiles on 5/8/20. +// + +#include + +OSStatus CMSampleBufferCreateFromData(NSSize size, + CMSampleTimingInfo timingInfo, + UInt64 sequenceNumber, NSData *data, + CMSampleBufferRef *sampleBuffer); + +OSStatus CMSampleBufferCreateFromDataNoCopy(NSSize size, + CMSampleTimingInfo timingInfo, + UInt64 sequenceNumber, NSData *data, + CMSampleBufferRef *sampleBuffer); + +CMSampleTimingInfo CMSampleTimingInfoForTimestamp(uint64_t timestampNanos, + uint32_t fpsNumerator, + uint32_t fpsDenominator); diff --git a/plugins/mac-virtualcam/src/dal-plugin/CMSampleBufferUtils.mm b/plugins/mac-virtualcam/src/dal-plugin/CMSampleBufferUtils.mm new file mode 100644 index 0000000..9273cc1 --- /dev/null +++ b/plugins/mac-virtualcam/src/dal-plugin/CMSampleBufferUtils.mm @@ -0,0 +1,187 @@ +// +// CMSampleBufferUtils.m +// dal-plugin +// +// Created by John Boiles on 5/8/20. +// + +#import "CMSampleBufferUtils.h" + +#include "Logging.h" + +/*! +CMSampleBufferCreateFromData + +Creates a CMSampleBuffer by copying bytes from NSData into a CVPixelBuffer. +*/ +OSStatus CMSampleBufferCreateFromData(NSSize size, + CMSampleTimingInfo timingInfo, + UInt64 sequenceNumber, NSData *data, + CMSampleBufferRef *sampleBuffer) +{ + OSStatus err = noErr; + + // Create an empty pixel buffer + CVPixelBufferRef pixelBuffer; + err = CVPixelBufferCreate(kCFAllocatorDefault, size.width, size.height, + kCVPixelFormatType_422YpCbCr8, nil, + &pixelBuffer); + if (err != noErr) { + DLog(@"CVPixelBufferCreate err %d", err); + return err; + } + + // Generate the video format description from that pixel buffer + CMFormatDescriptionRef format; + err = CMVideoFormatDescriptionCreateForImageBuffer(NULL, pixelBuffer, + &format); + if (err != noErr) { + DLog(@"CMVideoFormatDescriptionCreateForImageBuffer err %d", + err); + return err; + } + + // Copy memory into the pixel buffer + CVPixelBufferLockBaseAddress(pixelBuffer, 0); + uint8_t *dest = + (uint8_t *)CVPixelBufferGetBaseAddressOfPlane(pixelBuffer, 0); + uint8_t *src = (uint8_t *)data.bytes; + + size_t destBytesPerRow = + CVPixelBufferGetBytesPerRowOfPlane(pixelBuffer, 0); + size_t srcBytesPerRow = size.width * 2; + + // Sometimes CVPixelBufferCreate will create a pixelbuffer that's a different + // size than necessary to hold the frame (probably for some optimization reason). + // If that is the case this will do a row-by-row copy into the buffer. + if (destBytesPerRow == srcBytesPerRow) { + memcpy(dest, src, data.length); + } else { + for (int line = 0; line < size.height; line++) { + memcpy(dest, src, srcBytesPerRow); + src += srcBytesPerRow; + dest += destBytesPerRow; + } + } + + CVPixelBufferUnlockBaseAddress(pixelBuffer, 0); + + err = CMIOSampleBufferCreateForImageBuffer(kCFAllocatorDefault, + pixelBuffer, format, + &timingInfo, sequenceNumber, + 0, sampleBuffer); + CFRelease(format); + CFRelease(pixelBuffer); + + if (err != noErr) { + DLog(@"CMIOSampleBufferCreateForImageBuffer err %d", err); + return err; + } + + return noErr; +} + +static void releaseNSData(void *o, void *block, size_t size) +{ + NSData *data = (__bridge_transfer NSData *)o; + data = nil; // Assuming ARC is enabled +} + +// From https://stackoverflow.com/questions/26158253/how-to-create-a-cmblockbufferref-from-nsdata +OSStatus createReadonlyBlockBuffer(CMBlockBufferRef *result, NSData *data) +{ + CMBlockBufferCustomBlockSource blockSource = { + .version = kCMBlockBufferCustomBlockSourceVersion, + .AllocateBlock = NULL, + .FreeBlock = &releaseNSData, + .refCon = (__bridge_retained void *)data, + }; + return CMBlockBufferCreateWithMemoryBlock(NULL, (void *)data.bytes, + data.length, NULL, + &blockSource, 0, data.length, + 0, result); +} + +/*! + CMSampleBufferCreateFromDataNoCopy + + Creates a CMSampleBuffer by using the bytes directly from NSData (without copying them). + Seems to mostly work but does not work at full resolution in OBS for some reason (which prevents loopback testing). + */ +OSStatus CMSampleBufferCreateFromDataNoCopy(NSSize size, + CMSampleTimingInfo timingInfo, + UInt64 sequenceNumber, NSData *data, + CMSampleBufferRef *sampleBuffer) +{ + OSStatus err = noErr; + + CMBlockBufferRef dataBuffer; + createReadonlyBlockBuffer(&dataBuffer, data); + + // Magic format properties snagged from https://github.com/lvsti/CoreMediaIO-DAL-Example/blob/0392cbf27ed33425a1a5bd9f495b2ccec8f20501/Sources/Extras/CoreMediaIO/DeviceAbstractionLayer/Devices/Sample/PlugIn/CMIO_DP_Sample_Stream.cpp#L830 + NSDictionary *extensions = @{ + @"com.apple.cmio.format_extension.video.only_has_i_frames": + @YES, + (__bridge NSString *) + kCMFormatDescriptionExtension_FieldCount: @1, + (__bridge NSString *) + kCMFormatDescriptionExtension_ColorPrimaries: + (__bridge NSString *) + kCMFormatDescriptionColorPrimaries_SMPTE_C, + (__bridge NSString *) + kCMFormatDescriptionExtension_TransferFunction: ( + __bridge NSString *) + kCMFormatDescriptionTransferFunction_ITU_R_709_2, + (__bridge NSString *) + kCMFormatDescriptionExtension_YCbCrMatrix: (__bridge NSString *) + kCMFormatDescriptionYCbCrMatrix_ITU_R_601_4, + (__bridge NSString *) + kCMFormatDescriptionExtension_BytesPerRow: @(size.width * 2), + (__bridge NSString *)kCMFormatDescriptionExtension_FormatName: + @"Component Video - CCIR-601 uyvy", + (__bridge NSString *)kCMFormatDescriptionExtension_Version: @2, + }; + + CMFormatDescriptionRef format; + err = CMVideoFormatDescriptionCreate( + NULL, kCMVideoCodecType_422YpCbCr8, size.width, size.height, + (__bridge CFDictionaryRef)extensions, &format); + if (err != noErr) { + DLog(@"CMVideoFormatDescriptionCreate err %d", err); + return err; + } + + size_t dataSize = data.length; + err = CMIOSampleBufferCreate(kCFAllocatorDefault, dataBuffer, format, 1, + 1, &timingInfo, 1, &dataSize, + sequenceNumber, 0, sampleBuffer); + CFRelease(format); + CFRelease(dataBuffer); + + if (err != noErr) { + DLog(@"CMIOSampleBufferCreate err %d", err); + return err; + } + + return noErr; +} + +CMSampleTimingInfo CMSampleTimingInfoForTimestamp(uint64_t timestampNanos, + uint32_t fpsNumerator, + uint32_t fpsDenominator) +{ + // The timing here is quite important. For frames to be delivered correctly and successfully be recorded by apps + // like QuickTime Player, we need to be accurate in both our timestamps _and_ have a sensible scale. Using large + // timestamps and scales like mach_absolute_time() and NSEC_PER_SEC will work for display, but will error out + // when trying to record. + // + // 600 is a commmon default in Apple's docs https://developer.apple.com/documentation/avfoundation/avmutablemovie/1390622-timescale + CMTimeScale scale = 600; + CMSampleTimingInfo timing; + timing.duration = + CMTimeMake(fpsDenominator * scale, fpsNumerator * scale); + timing.presentationTimeStamp = CMTimeMake( + (timestampNanos / (double)NSEC_PER_SEC) * scale, scale); + timing.decodeTimeStamp = kCMTimeInvalid; + return timing; +} diff --git a/plugins/mac-virtualcam/src/dal-plugin/CMakeLists.txt b/plugins/mac-virtualcam/src/dal-plugin/CMakeLists.txt new file mode 100644 index 0000000..9224985 --- /dev/null +++ b/plugins/mac-virtualcam/src/dal-plugin/CMakeLists.txt @@ -0,0 +1,109 @@ +# Universal build for Apple Silicon +set(CMAKE_OSX_ARCHITECTURES "x86_64;arm64") + +project(mac-dal-plugin) + +find_library(AVFOUNDATION AVFoundation) +find_library(COCOA Cocoa) +find_library(COREFOUNDATION CoreFoundation) +find_library(COREMEDIA CoreMedia) +find_library(COREVIDEO CoreVideo) +find_library(COCOA Cocoa) +find_library(COREMEDIAIO CoreMediaIO) +find_library(IOSURFACE IOSurface) +find_library(IOKIT IOKit) + +# Possible we could remove osme of these +include_directories(${AVFOUNDATION} + ${COCOA} + ${COREFOUNDATION} + ${COREMEDIA} + ${COREVIDEO} + ${COREMEDIAIO} + ${COCOA} + ${IOSURFACE} + ./ + ../common) + +set(mac-dal-plugin_HEADERS + Defines.h + Logging.h + OBSDALPlugInInterface.h + OBSDALObjectStore.h + OBSDALPlugIn.h + OBSDALDevice.h + OBSDALStream.h + CMSampleBufferUtils.h + OBSDALMachClient.h + ../common/MachProtocol.h) + +set(mac-dal-plugin_SOURCES + OBSDALPlugInMain.mm + OBSDALPlugInInterface.mm + OBSDALObjectStore.mm + OBSDALPlugIn.mm + OBSDALDevice.mm + OBSDALStream.mm + CMSampleBufferUtils.mm + OBSDALMachClient.mm) + +add_library(mac-dal-plugin MODULE + ${mac-dal-plugin_SOURCES} + ${mac-dal-plugin_HEADERS}) + +set_target_properties(mac-dal-plugin PROPERTIES + FOLDER "plugins" + BUNDLE TRUE + OUTPUT_NAME "obs-mac-virtualcam" + COMPILE_FLAGS "-std=gnu++14 -stdlib=libc++ -fobjc-arc -fobjc-weak") + +if (XCODE) + set(TARGET_DIR "${CMAKE_CURRENT_BINARY_DIR}/Debug") +else (XCODE) + set(TARGET_DIR "${CMAKE_CURRENT_BINARY_DIR}") +endif (XCODE) + +target_link_libraries(mac-dal-plugin + ${AVFOUNDATION} + ${COCOA} + ${COREFOUNDATION} + ${COREMEDIA} + ${COREVIDEO} + ${COREMEDIAIO} + ${IOSURFACE} + ${IOKIT}) + +add_custom_command(TARGET mac-dal-plugin + POST_BUILD + COMMAND rm -rf ${TARGET_DIR}/obs-mac-virtualcam.plugin || true + COMMAND ${CMAKE_COMMAND} -E copy_directory ${TARGET_DIR}/obs-mac-virtualcam.bundle ${TARGET_DIR}/obs-mac-virtualcam.plugin + COMMENT "Rename bundle to plugin" +) + +# Note: Xcode seems to run a command `builtin-infoPlistUtility` to generate the Info.plist, but I'm +# not sure where to find that binary. If we had access to it, the command would look something like: +# builtin-infoPlistUtility ${PROJECT_SOURCE_DIR}/../common/CoreMediaIO/DeviceAbstractionLayer/Devices/Sample/PlugIn/SampleVCam-Info.plist -producttype com.apple.product-type.bundle -expandbuildsettings -platform macosx -o mac-virtualcam.bundle/Contents/Info.plist +# Instead, just copy in one that was already generated from Xcode. +add_custom_command(TARGET mac-dal-plugin + POST_BUILD + COMMAND cp ${PROJECT_SOURCE_DIR}/Info.plist ${TARGET_DIR}/obs-mac-virtualcam.plugin/Contents/Info.plist + COMMAND mkdir ${TARGET_DIR}/obs-mac-virtualcam.plugin/Contents/Resources + COMMAND cp ${PROJECT_SOURCE_DIR}/placeholder.png ${TARGET_DIR}/obs-mac-virtualcam.plugin/Contents/Resources/placeholder.png + COMMAND /usr/bin/plutil -insert CFBundleVersion -string "${OBS_VERSION}" ${TARGET_DIR}/obs-mac-virtualcam.plugin/Contents/Info.plist + COMMAND /usr/bin/plutil -insert CFBundleShortVersionString -string "${OBS_VERSION}" ${TARGET_DIR}/obs-mac-virtualcam.plugin/Contents/Info.plist + DEPENDS {PROJECT_SOURCE_DIR}/Info.plist + COMMENT "Copy in Info.plist" +) + +add_custom_command(TARGET mac-dal-plugin + POST_BUILD + COMMAND /usr/bin/codesign --force --deep --sign - --timestamp=none ${TARGET_DIR}/obs-mac-virtualcam.plugin + COMMENT "Codesign plugin" +) + +add_custom_command(TARGET mac-dal-plugin + POST_BUILD + COMMAND rm -rf "${OBS_OUTPUT_DIR}/$/data/obs-mac-virtualcam.plugin" || true + COMMAND ${CMAKE_COMMAND} -E copy_directory ${TARGET_DIR}/obs-mac-virtualcam.plugin "${OBS_OUTPUT_DIR}/$/data/obs-mac-virtualcam.plugin" + COMMENT "Copy plugin to destination" +) diff --git a/plugins/mac-virtualcam/src/dal-plugin/Defines.h b/plugins/mac-virtualcam/src/dal-plugin/Defines.h new file mode 100755 index 0000000..1d1705a --- /dev/null +++ b/plugins/mac-virtualcam/src/dal-plugin/Defines.h @@ -0,0 +1,21 @@ +// +// Defines.h +// obs-mac-virtualcam +// +// Created by John Boiles on 5/27/20. +// +// obs-mac-virtualcam is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 2 of the License, or +// (at your option) any later version. +// +// obs-mac-virtualcam is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with obs-mac-virtualcam. If not, see . + +#define PLUGIN_NAME @"mac-virtualcam" +#define PLUGIN_VERSION @"1.3.0" diff --git a/plugins/mac-virtualcam/src/dal-plugin/Info.plist b/plugins/mac-virtualcam/src/dal-plugin/Info.plist new file mode 100644 index 0000000..4dd87c9 --- /dev/null +++ b/plugins/mac-virtualcam/src/dal-plugin/Info.plist @@ -0,0 +1,40 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + obs-mac-virtualcam + CFBundleIdentifier + com.obsproject.obs-mac-virtualcam.dal-plugin + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + OBS Virtual Camera + CFBundlePackageType + BNDL + CFBundleSupportedPlatforms + + MacOSX + + CFPlugInFactories + + 7E950B8C-5E49-4B9E-B7D0-B3608A08E8F6 + PlugInMain + + CFPlugInTypes + + 30010C1C-93BF-11D8-8B5B-000A95AF9C6A + + 7E950B8C-5E49-4B9E-B7D0-B3608A08E8F6 + + + LSMinimumSystemVersion + 10.13 + CMIOHardwareAssistantServiceNames + + com.obsproject.obs-mac-virtualcam.server + + + diff --git a/plugins/mac-virtualcam/src/dal-plugin/Logging.h b/plugins/mac-virtualcam/src/dal-plugin/Logging.h new file mode 100644 index 0000000..d64a687 --- /dev/null +++ b/plugins/mac-virtualcam/src/dal-plugin/Logging.h @@ -0,0 +1,32 @@ +// +// Logging.h +// obs-mac-virtualcam +// +// Created by John Boiles on 4/10/20. +// +// obs-mac-virtualcam is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 2 of the License, or +// (at your option) any later version. +// +// obs-mac-virtualcam is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with obs-mac-virtualcam. If not, see . + +#ifndef Logging_h +#define Logging_h + +#include "Defines.h" + +#define DLog(fmt, ...) NSLog((PLUGIN_NAME @"(DAL): " fmt), ##__VA_ARGS__) +#define DLogFunc(fmt, ...) \ + NSLog((PLUGIN_NAME @"(DAL): %s " fmt), __FUNCTION__, ##__VA_ARGS__) +#define VLog(fmt, ...) +#define VLogFunc(fmt, ...) +#define ELog(fmt, ...) DLog(fmt, ##__VA_ARGS__) + +#endif /* Logging_h */ diff --git a/plugins/mac-virtualcam/src/dal-plugin/OBSDALDevice.h b/plugins/mac-virtualcam/src/dal-plugin/OBSDALDevice.h new file mode 100644 index 0000000..06f4ddf --- /dev/null +++ b/plugins/mac-virtualcam/src/dal-plugin/OBSDALDevice.h @@ -0,0 +1,34 @@ +// +// Device.h +// obs-mac-virtualcam +// +// Created by John Boiles on 4/10/20. +// +// obs-mac-virtualcam is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 2 of the License, or +// (at your option) any later version. +// +// obs-mac-virtualcam is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with obs-mac-virtualcam. If not, see . + +#import + +#import "OBSDALObjectStore.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface OBSDALDevice : NSObject + +@property CMIOObjectID objectId; +@property CMIOObjectID pluginId; +@property CMIOObjectID streamId; + +@end + +NS_ASSUME_NONNULL_END diff --git a/plugins/mac-virtualcam/src/dal-plugin/OBSDALDevice.mm b/plugins/mac-virtualcam/src/dal-plugin/OBSDALDevice.mm new file mode 100644 index 0000000..3cced11 --- /dev/null +++ b/plugins/mac-virtualcam/src/dal-plugin/OBSDALDevice.mm @@ -0,0 +1,295 @@ +// +// Device.mm +// obs-mac-virtualcam +// +// Created by John Boiles on 4/10/20. +// +// obs-mac-virtualcam is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 2 of the License, or +// (at your option) any later version. +// +// obs-mac-virtualcam is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with obs-mac-virtualcam. If not, see . + +#import "OBSDALDevice.h" + +#import +#include + +#import "OBSDALPlugin.h" +#import "Logging.h" + +@interface OBSDALDevice () +@property BOOL excludeNonDALAccess; +@property pid_t masterPid; +@end + +@implementation OBSDALDevice + +// Note that the DAL's API calls HasProperty before calling GetPropertyDataSize. This means that it can be assumed that address is valid for the property involved. +- (UInt32)getPropertyDataSizeWithAddress:(CMIOObjectPropertyAddress)address + qualifierDataSize:(UInt32)qualifierDataSize + qualifierData:(nonnull const void *)qualifierData +{ + + switch (address.mSelector) { + case kCMIOObjectPropertyName: + return sizeof(CFStringRef); + case kCMIOObjectPropertyManufacturer: + return sizeof(CFStringRef); + case kCMIOObjectPropertyElementCategoryName: + return sizeof(CFStringRef); + case kCMIOObjectPropertyElementNumberName: + return sizeof(CFStringRef); + case kCMIODevicePropertyPlugIn: + return sizeof(CMIOObjectID); + case kCMIODevicePropertyDeviceUID: + return sizeof(CFStringRef); + case kCMIODevicePropertyModelUID: + return sizeof(CFStringRef); + case kCMIODevicePropertyTransportType: + return sizeof(UInt32); + case kCMIODevicePropertyDeviceIsAlive: + return sizeof(UInt32); + case kCMIODevicePropertyDeviceHasChanged: + return sizeof(UInt32); + case kCMIODevicePropertyDeviceIsRunning: + return sizeof(UInt32); + case kCMIODevicePropertyDeviceIsRunningSomewhere: + return sizeof(UInt32); + case kCMIODevicePropertyDeviceCanBeDefaultDevice: + return sizeof(UInt32); + case kCMIODevicePropertyHogMode: + return sizeof(pid_t); + case kCMIODevicePropertyLatency: + return sizeof(UInt32); + case kCMIODevicePropertyStreams: + // Only one stream + return sizeof(CMIOStreamID) * 1; + case kCMIODevicePropertyStreamConfiguration: + // Only one stream + return sizeof(UInt32) + (sizeof(UInt32) * 1); + case kCMIODevicePropertyExcludeNonDALAccess: + return sizeof(UInt32); + case kCMIODevicePropertyCanProcessAVCCommand: + return sizeof(Boolean); + case kCMIODevicePropertyCanProcessRS422Command: + return sizeof(Boolean); + case kCMIODevicePropertyLinkedCoreAudioDeviceUID: + return sizeof(CFStringRef); + case kCMIODevicePropertyDeviceMaster: + return sizeof(pid_t); + default: + DLog(@"Device unhandled getPropertyDataSizeWithAddress for %@", + [OBSDALObjectStore + StringFromPropertySelector:address.mSelector]); + }; + + return 0; +} + +// Note that the DAL's API calls HasProperty before calling GetPropertyData. This means that it can be assumed that address is valid for the property involved. +- (void)getPropertyDataWithAddress:(CMIOObjectPropertyAddress)address + qualifierDataSize:(UInt32)qualifierDataSize + qualifierData:(nonnull const void *)qualifierData + dataSize:(UInt32)dataSize + dataUsed:(nonnull UInt32 *)dataUsed + data:(nonnull void *)data +{ + + switch (address.mSelector) { + case kCMIOObjectPropertyName: + *static_cast(data) = CFSTR("OBS Virtual Camera"); + *dataUsed = sizeof(CFStringRef); + break; + case kCMIOObjectPropertyManufacturer: + *static_cast(data) = CFSTR("John Boiles"); + *dataUsed = sizeof(CFStringRef); + break; + case kCMIOObjectPropertyElementCategoryName: + *static_cast(data) = CFSTR("Virtual Camera"); + *dataUsed = sizeof(CFStringRef); + break; + case kCMIOObjectPropertyElementNumberName: + *static_cast(data) = CFSTR("0001"); + *dataUsed = sizeof(CFStringRef); + break; + case kCMIODevicePropertyPlugIn: + *static_cast(data) = self.pluginId; + *dataUsed = sizeof(CMIOObjectID); + break; + case kCMIODevicePropertyDeviceUID: + *static_cast(data) = + CFSTR("obs-virtual-cam-device"); + *dataUsed = sizeof(CFStringRef); + break; + case kCMIODevicePropertyModelUID: + *static_cast(data) = + CFSTR("obs-virtual-cam-model"); + *dataUsed = sizeof(CFStringRef); + break; + case kCMIODevicePropertyTransportType: + *static_cast(data) = + kIOAudioDeviceTransportTypeBuiltIn; + *dataUsed = sizeof(UInt32); + break; + case kCMIODevicePropertyDeviceIsAlive: + *static_cast(data) = 1; + *dataUsed = sizeof(UInt32); + break; + case kCMIODevicePropertyDeviceHasChanged: + *static_cast(data) = 0; + *dataUsed = sizeof(UInt32); + break; + case kCMIODevicePropertyDeviceIsRunning: + *static_cast(data) = 1; + *dataUsed = sizeof(UInt32); + break; + case kCMIODevicePropertyDeviceIsRunningSomewhere: + *static_cast(data) = 1; + *dataUsed = sizeof(UInt32); + break; + case kCMIODevicePropertyDeviceCanBeDefaultDevice: + *static_cast(data) = 1; + *dataUsed = sizeof(UInt32); + break; + case kCMIODevicePropertyHogMode: + *static_cast(data) = -1; + *dataUsed = sizeof(pid_t); + break; + case kCMIODevicePropertyLatency: + *static_cast(data) = 0; + *dataUsed = sizeof(UInt32); + break; + case kCMIODevicePropertyStreams: + *static_cast(data) = self.streamId; + *dataUsed = sizeof(CMIOObjectID); + break; + case kCMIODevicePropertyStreamConfiguration: + DLog(@"TODO kCMIODevicePropertyStreamConfiguration"); + break; + case kCMIODevicePropertyExcludeNonDALAccess: + *static_cast(data) = self.excludeNonDALAccess ? 1 : 0; + *dataUsed = sizeof(UInt32); + break; + case kCMIODevicePropertyCanProcessAVCCommand: + *static_cast(data) = false; + *dataUsed = sizeof(Boolean); + break; + case kCMIODevicePropertyCanProcessRS422Command: + *static_cast(data) = false; + *dataUsed = sizeof(Boolean); + break; + case kCMIODevicePropertyDeviceMaster: + *static_cast(data) = self.masterPid; + *dataUsed = sizeof(pid_t); + break; + default: + DLog(@"Device unhandled getPropertyDataWithAddress for %@", + [OBSDALObjectStore + StringFromPropertySelector:address.mSelector]); + *dataUsed = 0; + break; + }; +} + +- (BOOL)hasPropertyWithAddress:(CMIOObjectPropertyAddress)address +{ + switch (address.mSelector) { + case kCMIOObjectPropertyName: + case kCMIOObjectPropertyManufacturer: + case kCMIOObjectPropertyElementCategoryName: + case kCMIOObjectPropertyElementNumberName: + case kCMIODevicePropertyPlugIn: + case kCMIODevicePropertyDeviceUID: + case kCMIODevicePropertyModelUID: + case kCMIODevicePropertyTransportType: + case kCMIODevicePropertyDeviceIsAlive: + case kCMIODevicePropertyDeviceHasChanged: + case kCMIODevicePropertyDeviceIsRunning: + case kCMIODevicePropertyDeviceIsRunningSomewhere: + case kCMIODevicePropertyDeviceCanBeDefaultDevice: + case kCMIODevicePropertyHogMode: + case kCMIODevicePropertyLatency: + case kCMIODevicePropertyStreams: + case kCMIODevicePropertyExcludeNonDALAccess: + case kCMIODevicePropertyCanProcessAVCCommand: + case kCMIODevicePropertyCanProcessRS422Command: + case kCMIODevicePropertyDeviceMaster: + return true; + case kCMIODevicePropertyStreamConfiguration: + case kCMIODevicePropertyLinkedCoreAudioDeviceUID: + return false; + default: + DLog(@"Device unhandled hasPropertyWithAddress for %@", + [OBSDALObjectStore + StringFromPropertySelector:address.mSelector]); + return false; + }; +} + +- (BOOL)isPropertySettableWithAddress:(CMIOObjectPropertyAddress)address +{ + switch (address.mSelector) { + case kCMIOObjectPropertyName: + case kCMIOObjectPropertyManufacturer: + case kCMIOObjectPropertyElementCategoryName: + case kCMIOObjectPropertyElementNumberName: + case kCMIODevicePropertyPlugIn: + case kCMIODevicePropertyDeviceUID: + case kCMIODevicePropertyModelUID: + case kCMIODevicePropertyTransportType: + case kCMIODevicePropertyDeviceIsAlive: + case kCMIODevicePropertyDeviceHasChanged: + case kCMIODevicePropertyDeviceIsRunning: + case kCMIODevicePropertyDeviceIsRunningSomewhere: + case kCMIODevicePropertyDeviceCanBeDefaultDevice: + case kCMIODevicePropertyHogMode: + case kCMIODevicePropertyLatency: + case kCMIODevicePropertyStreams: + case kCMIODevicePropertyStreamConfiguration: + case kCMIODevicePropertyCanProcessAVCCommand: + case kCMIODevicePropertyCanProcessRS422Command: + case kCMIODevicePropertyLinkedCoreAudioDeviceUID: + return false; + case kCMIODevicePropertyExcludeNonDALAccess: + case kCMIODevicePropertyDeviceMaster: + return true; + default: + DLog(@"Device unhandled isPropertySettableWithAddress for %@", + [OBSDALObjectStore + StringFromPropertySelector:address.mSelector]); + return false; + }; +} + +- (void)setPropertyDataWithAddress:(CMIOObjectPropertyAddress)address + qualifierDataSize:(UInt32)qualifierDataSize + qualifierData:(nonnull const void *)qualifierData + dataSize:(UInt32)dataSize + data:(nonnull const void *)data +{ + + switch (address.mSelector) { + case kCMIODevicePropertyExcludeNonDALAccess: + self.excludeNonDALAccess = + (*static_cast(data) != 0); + break; + case kCMIODevicePropertyDeviceMaster: + self.masterPid = *static_cast(data); + break; + default: + DLog(@"Device unhandled setPropertyDataWithAddress for %@", + [OBSDALObjectStore + StringFromPropertySelector:address.mSelector]); + break; + }; +} + +@end diff --git a/plugins/mac-virtualcam/src/dal-plugin/OBSDALMachClient.h b/plugins/mac-virtualcam/src/dal-plugin/OBSDALMachClient.h new file mode 100644 index 0000000..54ba4be --- /dev/null +++ b/plugins/mac-virtualcam/src/dal-plugin/OBSDALMachClient.h @@ -0,0 +1,33 @@ +// +// MachClient.h +// dal-plugin +// +// Created by John Boiles on 5/5/20. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +@protocol MachClientDelegate + +- (void)receivedFrameWithSize:(NSSize)size + timestamp:(uint64_t)timestamp + fpsNumerator:(uint32_t)fpsNumerator + fpsDenominator:(uint32_t)fpsDenominator + frameData:(NSData *)frameData; +- (void)receivedStop; + +@end + +@interface OBSDALMachClient : NSObject + +@property (nullable, weak) id delegate; + +- (BOOL)isServerAvailable; + +- (BOOL)connectToServer; + +@end + +NS_ASSUME_NONNULL_END diff --git a/plugins/mac-virtualcam/src/dal-plugin/OBSDALMachClient.mm b/plugins/mac-virtualcam/src/dal-plugin/OBSDALMachClient.mm new file mode 100644 index 0000000..8279cf3 --- /dev/null +++ b/plugins/mac-virtualcam/src/dal-plugin/OBSDALMachClient.mm @@ -0,0 +1,140 @@ +// +// MachClient.m +// dal-plugin +// +// Created by John Boiles on 5/5/20. +// + +#import "OBSDALMachClient.h" +#import "MachProtocol.h" +#import "Logging.h" + +@interface OBSDALMachClient () { + NSPort *_receivePort; +} +@end + +@implementation OBSDALMachClient + +- (void)dealloc +{ + DLogFunc(@""); + _receivePort.delegate = nil; +} + +- (NSPort *)serverPort +{ +// See note in MachServer.mm and don't judge me +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + return [[NSMachBootstrapServer sharedInstance] + portForName:@MACH_SERVICE_NAME]; +#pragma clang diagnostic pop +} + +- (BOOL)isServerAvailable +{ + return [self serverPort] != nil; +} + +- (NSPort *)receivePort +{ + if (_receivePort == nil) { + NSPort *receivePort = [NSMachPort port]; + _receivePort = receivePort; + _receivePort.delegate = self; + __weak __typeof(self) weakSelf = self; + dispatch_async( + dispatch_get_global_queue( + DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), + ^{ + NSRunLoop *runLoop = [NSRunLoop currentRunLoop]; + [runLoop addPort:receivePort + forMode:NSDefaultRunLoopMode]; + // weakSelf should become nil when this object gets destroyed + while (weakSelf) { + [[NSRunLoop currentRunLoop] + runUntilDate: + [NSDate dateWithTimeIntervalSinceNow: + 0.1]]; + } + DLog(@"Shutting down receive run loop"); + }); + DLog(@"Initialized mach port %d for receiving", + ((NSMachPort *)_receivePort).machPort); + } + return _receivePort; +} + +- (BOOL)connectToServer +{ + DLogFunc(@""); + + NSPort *sendPort = [self serverPort]; + if (sendPort == nil) { + ELog(@"Unable to connect to server port"); + return NO; + } + + NSPortMessage *message = [[NSPortMessage alloc] + initWithSendPort:sendPort + receivePort:self.receivePort + components:nil]; + message.msgid = MachMsgIdConnect; + + NSDate *timeout = [NSDate dateWithTimeIntervalSinceNow:5.0]; + if (![message sendBeforeDate:timeout]) { + ELog(@"sendBeforeDate failed"); + return NO; + } + + return YES; +} + +- (void)handlePortMessage:(NSPortMessage *)message +{ + VLogFunc(@""); + NSArray *components = message.components; + switch (message.msgid) { + case MachMsgIdConnect: + DLog(@"Received connect response"); + break; + case MachMsgIdFrame: + VLog(@"Received frame message"); + if (components.count >= 6) { + CGFloat width; + [components[0] getBytes:&width length:sizeof(width)]; + CGFloat height; + [components[1] getBytes:&height length:sizeof(height)]; + uint64_t timestamp; + [components[2] getBytes:×tamp + length:sizeof(timestamp)]; + VLog(@"Received frame data: %fx%f (%llu)", width, + height, timestamp); + NSData *frameData = components[3]; + uint32_t fpsNumerator; + [components[4] getBytes:&fpsNumerator + length:sizeof(fpsNumerator)]; + uint32_t fpsDenominator; + [components[5] getBytes:&fpsDenominator + length:sizeof(fpsDenominator)]; + [self.delegate + receivedFrameWithSize:NSMakeSize(width, height) + timestamp:timestamp + fpsNumerator:fpsNumerator + fpsDenominator:fpsDenominator + frameData:frameData]; + } + break; + case MachMsgIdStop: + DLog(@"Received stop message"); + [self.delegate receivedStop]; + break; + default: + ELog(@"Received unexpected response msgid %u", + (unsigned)message.msgid); + break; + } +} + +@end diff --git a/plugins/mac-virtualcam/src/dal-plugin/OBSDALObjectStore.h b/plugins/mac-virtualcam/src/dal-plugin/OBSDALObjectStore.h new file mode 100644 index 0000000..4c329d9 --- /dev/null +++ b/plugins/mac-virtualcam/src/dal-plugin/OBSDALObjectStore.h @@ -0,0 +1,62 @@ +// +// ObjectStore.h +// obs-mac-virtualcam +// +// Created by John Boiles on 4/10/20. +// +// obs-mac-virtualcam is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 2 of the License, or +// (at your option) any later version. +// +// obs-mac-virtualcam is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with obs-mac-virtualcam. If not, see . + +#import +#import + +NS_ASSUME_NONNULL_BEGIN + +@protocol CMIOObject + +- (BOOL)hasPropertyWithAddress:(CMIOObjectPropertyAddress)address; +- (BOOL)isPropertySettableWithAddress:(CMIOObjectPropertyAddress)address; +- (UInt32)getPropertyDataSizeWithAddress:(CMIOObjectPropertyAddress)address + qualifierDataSize:(UInt32)qualifierDataSize + qualifierData:(const void *)qualifierData; +- (void)getPropertyDataWithAddress:(CMIOObjectPropertyAddress)address + qualifierDataSize:(UInt32)qualifierDataSize + qualifierData:(const void *)qualifierData + dataSize:(UInt32)dataSize + dataUsed:(UInt32 *)dataUsed + data:(void *)data; +- (void)setPropertyDataWithAddress:(CMIOObjectPropertyAddress)address + qualifierDataSize:(UInt32)qualifierDataSize + qualifierData:(const void *)qualifierData + dataSize:(UInt32)dataSize + data:(const void *)data; + +@end + +@interface OBSDALObjectStore : NSObject + ++ (OBSDALObjectStore *)SharedObjectStore; + ++ (NSObject *)GetObjectWithId:(CMIOObjectID)objectId; + ++ (NSString *)StringFromPropertySelector:(CMIOObjectPropertySelector)selector; + ++ (BOOL)IsBridgedTypeForSelector:(CMIOObjectPropertySelector)selector; + +- (NSObject *)getObject:(CMIOObjectID)objectID; + +- (void)setObject:(id)object forObjectId:(CMIOObjectID)objectId; + +@end + +NS_ASSUME_NONNULL_END diff --git a/plugins/mac-virtualcam/src/dal-plugin/OBSDALObjectStore.mm b/plugins/mac-virtualcam/src/dal-plugin/OBSDALObjectStore.mm new file mode 100644 index 0000000..e6e58ed --- /dev/null +++ b/plugins/mac-virtualcam/src/dal-plugin/OBSDALObjectStore.mm @@ -0,0 +1,281 @@ +// +// ObjectStore.mm +// obs-mac-virtualcam +// +// Created by John Boiles on 4/10/20. +// +// obs-mac-virtualcam is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 2 of the License, or +// (at your option) any later version. +// +// obs-mac-virtualcam is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with obs-mac-virtualcam. If not, see . + +#import "OBSDALObjectStore.h" + +@interface OBSDALObjectStore () +@property NSMutableDictionary *objectMap; +@end + +@implementation OBSDALObjectStore + +// 4-byte selectors to string for easy debugging ++ (NSString *)StringFromPropertySelector:(CMIOObjectPropertySelector)selector +{ + switch (selector) { + case kCMIODevicePropertyPlugIn: + return @"kCMIODevicePropertyPlugIn"; + case kCMIODevicePropertyDeviceUID: + return @"kCMIODevicePropertyDeviceUID"; + case kCMIODevicePropertyModelUID: + return @"kCMIODevicePropertyModelUID"; + case kCMIODevicePropertyTransportType: + return @"kCMIODevicePropertyTransportType"; + case kCMIODevicePropertyDeviceIsAlive: + return @"kCMIODevicePropertyDeviceIsAlive"; + case kCMIODevicePropertyDeviceHasChanged: + return @"kCMIODevicePropertyDeviceHasChanged"; + case kCMIODevicePropertyDeviceIsRunning: + return @"kCMIODevicePropertyDeviceIsRunning"; + case kCMIODevicePropertyDeviceIsRunningSomewhere: + return @"kCMIODevicePropertyDeviceIsRunningSomewhere"; + case kCMIODevicePropertyDeviceCanBeDefaultDevice: + return @"kCMIODevicePropertyDeviceCanBeDefaultDevice"; + case kCMIODevicePropertyHogMode: + return @"kCMIODevicePropertyHogMode"; + case kCMIODevicePropertyLatency: + return @"kCMIODevicePropertyLatency"; + case kCMIODevicePropertyStreams: + return @"kCMIODevicePropertyStreams"; + case kCMIODevicePropertyStreamConfiguration: + return @"kCMIODevicePropertyStreamConfiguration"; + case kCMIODevicePropertyDeviceMaster: + return @"kCMIODevicePropertyDeviceMaster"; + case kCMIODevicePropertyExcludeNonDALAccess: + return @"kCMIODevicePropertyExcludeNonDALAccess"; + case kCMIODevicePropertyClientSyncDiscontinuity: + return @"kCMIODevicePropertyClientSyncDiscontinuity"; + case kCMIODevicePropertySMPTETimeCallback: + return @"kCMIODevicePropertySMPTETimeCallback"; + case kCMIODevicePropertyCanProcessAVCCommand: + return @"kCMIODevicePropertyCanProcessAVCCommand"; + case kCMIODevicePropertyAVCDeviceType: + return @"kCMIODevicePropertyAVCDeviceType"; + case kCMIODevicePropertyAVCDeviceSignalMode: + return @"kCMIODevicePropertyAVCDeviceSignalMode"; + case kCMIODevicePropertyCanProcessRS422Command: + return @"kCMIODevicePropertyCanProcessRS422Command"; + case kCMIODevicePropertyLinkedCoreAudioDeviceUID: + return @"kCMIODevicePropertyLinkedCoreAudioDeviceUID"; + case kCMIODevicePropertyVideoDigitizerComponents: + return @"kCMIODevicePropertyVideoDigitizerComponents"; + case kCMIODevicePropertySuspendedByUser: + return @"kCMIODevicePropertySuspendedByUser"; + case kCMIODevicePropertyLinkedAndSyncedCoreAudioDeviceUID: + return @"kCMIODevicePropertyLinkedAndSyncedCoreAudioDeviceUID"; + case kCMIODevicePropertyIIDCInitialUnitSpace: + return @"kCMIODevicePropertyIIDCInitialUnitSpace"; + case kCMIODevicePropertyIIDCCSRData: + return @"kCMIODevicePropertyIIDCCSRData"; + case kCMIODevicePropertyCanSwitchFrameRatesWithoutFrameDrops: + return @"kCMIODevicePropertyCanSwitchFrameRatesWithoutFrameDrops"; + case kCMIODevicePropertyLocation: + return @"kCMIODevicePropertyLocation"; + case kCMIODevicePropertyDeviceHasStreamingError: + return @"kCMIODevicePropertyDeviceHasStreamingError"; + case kCMIODevicePropertyScopeInput: + return @"kCMIODevicePropertyScopeInput"; + case kCMIODevicePropertyScopeOutput: + return @"kCMIODevicePropertyScopeOutput"; + case kCMIODevicePropertyScopePlayThrough: + return @"kCMIODevicePropertyScopePlayThrough"; + case kCMIOObjectPropertyClass: + return @"kCMIOObjectPropertyClass"; + case kCMIOObjectPropertyOwner: + return @"kCMIOObjectPropertyOwner"; + case kCMIOObjectPropertyCreator: + return @"kCMIOObjectPropertyCreator"; + case kCMIOObjectPropertyName: + return @"kCMIOObjectPropertyName"; + case kCMIOObjectPropertyManufacturer: + return @"kCMIOObjectPropertyManufacturer"; + case kCMIOObjectPropertyElementName: + return @"kCMIOObjectPropertyElementName"; + case kCMIOObjectPropertyElementCategoryName: + return @"kCMIOObjectPropertyElementCategoryName"; + case kCMIOObjectPropertyElementNumberName: + return @"kCMIOObjectPropertyElementNumberName"; + case kCMIOObjectPropertyOwnedObjects: + return @"kCMIOObjectPropertyOwnedObjects"; + case kCMIOObjectPropertyListenerAdded: + return @"kCMIOObjectPropertyListenerAdded"; + case kCMIOObjectPropertyListenerRemoved: + return @"kCMIOObjectPropertyListenerRemoved"; + case kCMIOStreamPropertyDirection: + return @"kCMIOStreamPropertyDirection"; + case kCMIOStreamPropertyTerminalType: + return @"kCMIOStreamPropertyTerminalType"; + case kCMIOStreamPropertyStartingChannel: + return @"kCMIOStreamPropertyStartingChannel"; + // Same value as kCMIODevicePropertyLatency + // case kCMIOStreamPropertyLatency: + // return @"kCMIOStreamPropertyLatency"; + case kCMIOStreamPropertyFormatDescription: + return @"kCMIOStreamPropertyFormatDescription"; + case kCMIOStreamPropertyFormatDescriptions: + return @"kCMIOStreamPropertyFormatDescriptions"; + case kCMIOStreamPropertyStillImage: + return @"kCMIOStreamPropertyStillImage"; + case kCMIOStreamPropertyStillImageFormatDescriptions: + return @"kCMIOStreamPropertyStillImageFormatDescriptions"; + case kCMIOStreamPropertyFrameRate: + return @"kCMIOStreamPropertyFrameRate"; + case kCMIOStreamPropertyMinimumFrameRate: + return @"kCMIOStreamPropertyMinimumFrameRate"; + case kCMIOStreamPropertyFrameRates: + return @"kCMIOStreamPropertyFrameRates"; + case kCMIOStreamPropertyFrameRateRanges: + return @"kCMIOStreamPropertyFrameRateRanges"; + case kCMIOStreamPropertyNoDataTimeoutInMSec: + return @"kCMIOStreamPropertyNoDataTimeoutInMSec"; + case kCMIOStreamPropertyDeviceSyncTimeoutInMSec: + return @"kCMIOStreamPropertyDeviceSyncTimeoutInMSec"; + case kCMIOStreamPropertyNoDataEventCount: + return @"kCMIOStreamPropertyNoDataEventCount"; + case kCMIOStreamPropertyOutputBufferUnderrunCount: + return @"kCMIOStreamPropertyOutputBufferUnderrunCount"; + case kCMIOStreamPropertyOutputBufferRepeatCount: + return @"kCMIOStreamPropertyOutputBufferRepeatCount"; + case kCMIOStreamPropertyOutputBufferQueueSize: + return @"kCMIOStreamPropertyOutputBufferQueueSize"; + case kCMIOStreamPropertyOutputBuffersRequiredForStartup: + return @"kCMIOStreamPropertyOutputBuffersRequiredForStartup"; + case kCMIOStreamPropertyOutputBuffersNeededForThrottledPlayback: + return @"kCMIOStreamPropertyOutputBuffersNeededForThrottledPlayback"; + case kCMIOStreamPropertyFirstOutputPresentationTimeStamp: + return @"kCMIOStreamPropertyFirstOutputPresentationTimeStamp"; + case kCMIOStreamPropertyEndOfData: + return @"kCMIOStreamPropertyEndOfData"; + case kCMIOStreamPropertyClock: + return @"kCMIOStreamPropertyClock"; + case kCMIOStreamPropertyCanProcessDeckCommand: + return @"kCMIOStreamPropertyCanProcessDeckCommand"; + case kCMIOStreamPropertyDeck: + return @"kCMIOStreamPropertyDeck"; + case kCMIOStreamPropertyDeckFrameNumber: + return @"kCMIOStreamPropertyDeckFrameNumber"; + case kCMIOStreamPropertyDeckDropness: + return @"kCMIOStreamPropertyDeckDropness"; + case kCMIOStreamPropertyDeckThreaded: + return @"kCMIOStreamPropertyDeckThreaded"; + case kCMIOStreamPropertyDeckLocal: + return @"kCMIOStreamPropertyDeckLocal"; + case kCMIOStreamPropertyDeckCueing: + return @"kCMIOStreamPropertyDeckCueing"; + case kCMIOStreamPropertyInitialPresentationTimeStampForLinkedAndSyncedAudio: + return @"kCMIOStreamPropertyInitialPresentationTimeStampForLinkedAndSyncedAudio"; + case kCMIOStreamPropertyScheduledOutputNotificationProc: + return @"kCMIOStreamPropertyScheduledOutputNotificationProc"; + case kCMIOStreamPropertyPreferredFormatDescription: + return @"kCMIOStreamPropertyPreferredFormatDescription"; + case kCMIOStreamPropertyPreferredFrameRate: + return @"kCMIOStreamPropertyPreferredFrameRate"; + case kCMIOControlPropertyScope: + return @"kCMIOControlPropertyScope"; + case kCMIOControlPropertyElement: + return @"kCMIOControlPropertyElement"; + case kCMIOControlPropertyVariant: + return @"kCMIOControlPropertyVariant"; + case kCMIOHardwarePropertyProcessIsMaster: + return @"kCMIOHardwarePropertyProcessIsMaster"; + case kCMIOHardwarePropertyIsInitingOrExiting: + return @"kCMIOHardwarePropertyIsInitingOrExiting"; + case kCMIOHardwarePropertyDevices: + return @"kCMIOHardwarePropertyDevices"; + case kCMIOHardwarePropertyDefaultInputDevice: + return @"kCMIOHardwarePropertyDefaultInputDevice"; + case kCMIOHardwarePropertyDefaultOutputDevice: + return @"kCMIOHardwarePropertyDefaultOutputDevice"; + case kCMIOHardwarePropertyDeviceForUID: + return @"kCMIOHardwarePropertyDeviceForUID"; + case kCMIOHardwarePropertySleepingIsAllowed: + return @"kCMIOHardwarePropertySleepingIsAllowed"; + case kCMIOHardwarePropertyUnloadingIsAllowed: + return @"kCMIOHardwarePropertyUnloadingIsAllowed"; + case kCMIOHardwarePropertyPlugInForBundleID: + return @"kCMIOHardwarePropertyPlugInForBundleID"; + case kCMIOHardwarePropertyUserSessionIsActiveOrHeadless: + return @"kCMIOHardwarePropertyUserSessionIsActiveOrHeadless"; + case kCMIOHardwarePropertySuspendedBySystem: + return @"kCMIOHardwarePropertySuspendedBySystem"; + case kCMIOHardwarePropertyAllowScreenCaptureDevices: + return @"kCMIOHardwarePropertyAllowScreenCaptureDevices"; + case kCMIOHardwarePropertyAllowWirelessScreenCaptureDevices: + return @"kCMIOHardwarePropertyAllowWirelessScreenCaptureDevices"; + default: + uint8_t *chars = (uint8_t *)&selector; + return [NSString stringWithFormat:@"Unknown selector: %c%c%c%c", + chars[0], chars[1], chars[2], + chars[3]]; + } +} + ++ (BOOL)IsBridgedTypeForSelector:(CMIOObjectPropertySelector)selector +{ + switch (selector) { + case kCMIOObjectPropertyName: + case kCMIOObjectPropertyManufacturer: + case kCMIOObjectPropertyElementName: + case kCMIOObjectPropertyElementCategoryName: + case kCMIOObjectPropertyElementNumberName: + case kCMIODevicePropertyDeviceUID: + case kCMIODevicePropertyModelUID: + case kCMIOStreamPropertyFormatDescriptions: + case kCMIOStreamPropertyFormatDescription: + case kCMIOStreamPropertyClock: + return YES; + default: + return NO; + } +} + ++ (OBSDALObjectStore *)SharedObjectStore +{ + static OBSDALObjectStore *sObjectStore = nil; + static dispatch_once_t sOnceToken; + dispatch_once(&sOnceToken, ^{ + sObjectStore = [[self alloc] init]; + }); + return sObjectStore; +} + ++ (NSObject *)GetObjectWithId:(CMIOObjectID)objectId +{ + return [[OBSDALObjectStore SharedObjectStore] getObject:objectId]; +} + +- (id)init +{ + if (self = [super init]) { + self.objectMap = [[NSMutableDictionary alloc] init]; + } + return self; +} + +- (NSObject *)getObject:(CMIOObjectID)objectID +{ + return self.objectMap[@(objectID)]; +} + +- (void)setObject:(id)object forObjectId:(CMIOObjectID)objectId +{ + self.objectMap[@(objectId)] = object; +} + +@end diff --git a/plugins/mac-virtualcam/src/dal-plugin/OBSDALPlugInInterface.h b/plugins/mac-virtualcam/src/dal-plugin/OBSDALPlugInInterface.h new file mode 100644 index 0000000..2116f08 --- /dev/null +++ b/plugins/mac-virtualcam/src/dal-plugin/OBSDALPlugInInterface.h @@ -0,0 +1,23 @@ +// +// PlugInInterface.h +// obs-mac-virtualcam +// +// Created by John Boiles on 4/9/20. +// +// obs-mac-virtualcam is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 2 of the License, or +// (at your option) any later version. +// +// obs-mac-virtualcam is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with obs-mac-virtualcam. If not, see . + +#import + +// The static singleton of the plugin interface +CMIOHardwarePlugInRef OBSDALPlugInRef(); diff --git a/plugins/mac-virtualcam/src/dal-plugin/OBSDALPlugInInterface.mm b/plugins/mac-virtualcam/src/dal-plugin/OBSDALPlugInInterface.mm new file mode 100644 index 0000000..20fea58 --- /dev/null +++ b/plugins/mac-virtualcam/src/dal-plugin/OBSDALPlugInInterface.mm @@ -0,0 +1,457 @@ +// +// PlugInInterface.mm +// obs-mac-virtualcam +// +// This file implements the CMIO DAL plugin interface +// +// Created by John Boiles on 4/9/20. +// +// obs-mac-virtualcam is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 2 of the License, or +// (at your option) any later version. +// +// obs-mac-virtualcam is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with obs-mac-virtualcam. If not, see . + +#import "OBSDALPlugInInterface.h" + +#import + +#import "OBSDALPlugin.h" +#import "OBSDALDevice.h" +#import "OBSDALStream.h" +#import "Logging.h" + +#pragma mark Plug-In Operations + +static UInt32 sRefCount = 0; + +ULONG HardwarePlugIn_AddRef(CMIOHardwarePlugInRef self) +{ + sRefCount += 1; + DLogFunc(@"sRefCount now = %d", sRefCount); + return sRefCount; +} + +ULONG HardwarePlugIn_Release(CMIOHardwarePlugInRef self) +{ + sRefCount -= 1; + DLogFunc(@"sRefCount now = %d", sRefCount); + return sRefCount; +} + +HRESULT HardwarePlugIn_QueryInterface(CMIOHardwarePlugInRef self, REFIID uuid, + LPVOID *interface) +{ + DLogFunc(@""); + + if (!interface) { + DLogFunc(@"Received an empty interface"); + return E_POINTER; + } + + // Set the returned interface to NULL in case the UUIDs don't match + *interface = NULL; + + // Create a CoreFoundation UUIDRef for the requested interface. + CFUUIDRef cfUuid = CFUUIDCreateFromUUIDBytes(kCFAllocatorDefault, uuid); + CFStringRef uuidString = CFUUIDCreateString(NULL, cfUuid); + CFStringRef hardwarePluginUuid = + CFUUIDCreateString(NULL, kCMIOHardwarePlugInInterfaceID); + + if (CFEqual(uuidString, hardwarePluginUuid)) { + // Return the interface; + sRefCount += 1; + *interface = OBSDALPlugInRef(); + return kCMIOHardwareNoError; + } else { + DLogFunc(@"ERR Queried for some weird UUID %@", uuidString); + } + + return E_NOINTERFACE; +} + +// I think this is deprecated, seems that HardwarePlugIn_InitializeWithObjectID gets called instead +OSStatus HardwarePlugIn_Initialize(CMIOHardwarePlugInRef self) +{ + DLogFunc(@"ERR self=%p", self); + return kCMIOHardwareUnspecifiedError; +} + +OSStatus HardwarePlugIn_InitializeWithObjectID(CMIOHardwarePlugInRef self, + CMIOObjectID objectID) +{ + DLogFunc(@"self=%p", self); + + OSStatus error = kCMIOHardwareNoError; + + OBSDALPlugin *plugIn = [OBSDALPlugin SharedPlugIn]; + plugIn.objectId = objectID; + [[OBSDALObjectStore SharedObjectStore] setObject:plugIn + forObjectId:objectID]; + + OBSDALDevice *device = [[OBSDALDevice alloc] init]; + CMIOObjectID deviceId; + error = CMIOObjectCreate(OBSDALPlugInRef(), kCMIOObjectSystemObject, + kCMIODeviceClassID, &deviceId); + if (error != noErr) { + DLog(@"CMIOObjectCreate Error %d", error); + return error; + } + device.objectId = deviceId; + device.pluginId = objectID; + [[OBSDALObjectStore SharedObjectStore] setObject:device + forObjectId:deviceId]; + + OBSDALStream *stream = [[OBSDALStream alloc] init]; + CMIOObjectID streamId; + error = CMIOObjectCreate(OBSDALPlugInRef(), deviceId, + kCMIOStreamClassID, &streamId); + if (error != noErr) { + DLog(@"CMIOObjectCreate Error %d", error); + return error; + } + stream.objectId = streamId; + [[OBSDALObjectStore SharedObjectStore] setObject:stream + forObjectId:streamId]; + device.streamId = streamId; + plugIn.stream = stream; + + // Tell the system about the Device + error = CMIOObjectsPublishedAndDied( + OBSDALPlugInRef(), kCMIOObjectSystemObject, 1, &deviceId, 0, 0); + if (error != kCMIOHardwareNoError) { + DLog(@"CMIOObjectsPublishedAndDied plugin/device Error %d", + error); + return error; + } + + // Tell the system about the Stream + error = CMIOObjectsPublishedAndDied(OBSDALPlugInRef(), deviceId, 1, + &streamId, 0, 0); + if (error != kCMIOHardwareNoError) { + DLog(@"CMIOObjectsPublishedAndDied device/stream Error %d", + error); + return error; + } + + return error; +} + +OSStatus HardwarePlugIn_Teardown(CMIOHardwarePlugInRef self) +{ + DLogFunc(@"self=%p", self); + + OSStatus error = kCMIOHardwareNoError; + + OBSDALPlugin *plugIn = [OBSDALPlugin SharedPlugIn]; + [plugIn teardown]; + + return error; +} + +#pragma mark CMIOObject Operations + +void HardwarePlugIn_ObjectShow(CMIOHardwarePlugInRef self, + CMIOObjectID objectID) +{ + DLogFunc(@"self=%p", self); +} + +Boolean +HardwarePlugIn_ObjectHasProperty(CMIOHardwarePlugInRef self, + CMIOObjectID objectID, + const CMIOObjectPropertyAddress *address) +{ + + NSObject *object = + [OBSDALObjectStore GetObjectWithId:objectID]; + + if (object == nil) { + DLogFunc(@"ERR nil object"); + return false; + } + + Boolean answer = [object hasPropertyWithAddress:*address]; + + // Disabling Noisy logs + // DLogFunc(@"%@(%d) %@ self=%p hasProperty=%d", NSStringFromClass([object class]), objectID, [ObjectStore StringFromPropertySelector:address->mSelector], self, answer); + + return answer; +} + +OSStatus HardwarePlugIn_ObjectIsPropertySettable( + CMIOHardwarePlugInRef self, CMIOObjectID objectID, + const CMIOObjectPropertyAddress *address, Boolean *isSettable) +{ + + NSObject *object = + [OBSDALObjectStore GetObjectWithId:objectID]; + + if (object == nil) { + DLogFunc(@"ERR nil object"); + return kCMIOHardwareBadObjectError; + } + + *isSettable = [object isPropertySettableWithAddress:*address]; + + DLogFunc(@"%@(%d) %@ self=%p settable=%d", + NSStringFromClass([object class]), objectID, + [OBSDALObjectStore + StringFromPropertySelector:address->mSelector], + self, *isSettable); + + return kCMIOHardwareNoError; +} + +OSStatus HardwarePlugIn_ObjectGetPropertyDataSize( + CMIOHardwarePlugInRef self, CMIOObjectID objectID, + const CMIOObjectPropertyAddress *address, UInt32 qualifierDataSize, + const void *qualifierData, UInt32 *dataSize) +{ + + NSObject *object = + [OBSDALObjectStore GetObjectWithId:objectID]; + + if (object == nil) { + DLogFunc(@"ERR nil object"); + return kCMIOHardwareBadObjectError; + } + + *dataSize = [object getPropertyDataSizeWithAddress:*address + qualifierDataSize:qualifierDataSize + qualifierData:qualifierData]; + + // Disabling Noisy logs + // DLogFunc(@"%@(%d) %@ self=%p size=%d", NSStringFromClass([object class]), objectID, [ObjectStore StringFromPropertySelector:address->mSelector], self, *dataSize); + + return kCMIOHardwareNoError; +} + +OSStatus HardwarePlugIn_ObjectGetPropertyData( + CMIOHardwarePlugInRef self, CMIOObjectID objectID, + const CMIOObjectPropertyAddress *address, UInt32 qualifierDataSize, + const void *qualifierData, UInt32 dataSize, UInt32 *dataUsed, + void *data) +{ + + NSObject *object = + [OBSDALObjectStore GetObjectWithId:objectID]; + + if (object == nil) { + DLogFunc(@"ERR nil object"); + return kCMIOHardwareBadObjectError; + } + + [object getPropertyDataWithAddress:*address + qualifierDataSize:qualifierDataSize + qualifierData:qualifierData + dataSize:dataSize + dataUsed:dataUsed + data:data]; + + // Disabling Noisy logs + // if ([ObjectStore IsBridgedTypeForSelector:address->mSelector]) { + // id dataObj = (__bridge NSObject *)*static_cast(data); + // DLogFunc(@"%@(%d) %@ self=%p data(id)=%@", NSStringFromClass([object class]), objectID, [ObjectStore StringFromPropertySelector:address->mSelector], self, dataObj); + // } else { + // UInt32 *dataInt = (UInt32 *)data; + // DLogFunc(@"%@(%d) %@ self=%p data(int)=%d", NSStringFromClass([object class]), objectID, [ObjectStore StringFromPropertySelector:address->mSelector], self, *dataInt); + // } + + return kCMIOHardwareNoError; +} + +OSStatus HardwarePlugIn_ObjectSetPropertyData( + CMIOHardwarePlugInRef self, CMIOObjectID objectID, + const CMIOObjectPropertyAddress *address, UInt32 qualifierDataSize, + const void *qualifierData, UInt32 dataSize, const void *data) +{ + + NSObject *object = + [OBSDALObjectStore GetObjectWithId:objectID]; + + if (object == nil) { + DLogFunc(@"ERR nil object"); + return kCMIOHardwareBadObjectError; + } + + UInt32 *dataInt = (UInt32 *)data; + DLogFunc(@"%@(%d) %@ self=%p data(int)=%d", + NSStringFromClass([object class]), objectID, + [OBSDALObjectStore + StringFromPropertySelector:address->mSelector], + self, *dataInt); + + [object setPropertyDataWithAddress:*address + qualifierDataSize:qualifierDataSize + qualifierData:qualifierData + dataSize:dataSize + data:data]; + + return kCMIOHardwareNoError; +} + +#pragma mark CMIOStream Operations +OSStatus HardwarePlugIn_StreamCopyBufferQueue( + CMIOHardwarePlugInRef self, CMIOStreamID streamID, + CMIODeviceStreamQueueAlteredProc queueAlteredProc, + void *queueAlteredRefCon, CMSimpleQueueRef *queue) +{ + + OBSDALStream *stream = + (OBSDALStream *)[OBSDALObjectStore GetObjectWithId:streamID]; + + if (stream == nil) { + DLogFunc(@"ERR nil object"); + return kCMIOHardwareBadObjectError; + } + + *queue = [stream copyBufferQueueWithAlteredProc:queueAlteredProc + alteredRefCon:queueAlteredRefCon]; + + DLogFunc(@"%@ (id=%d) self=%p queue=%@", stream, streamID, self, + (__bridge NSObject *)*queue); + + return kCMIOHardwareNoError; +} + +#pragma mark CMIODevice Operations +OSStatus HardwarePlugIn_DeviceStartStream(CMIOHardwarePlugInRef self, + CMIODeviceID deviceID, + CMIOStreamID streamID) +{ + DLogFunc(@"self=%p device=%d stream=%d", self, deviceID, streamID); + + OBSDALStream *stream = + (OBSDALStream *)[OBSDALObjectStore GetObjectWithId:streamID]; + + if (stream == nil) { + DLogFunc(@"ERR nil object"); + return kCMIOHardwareBadObjectError; + } + + [[OBSDALPlugin SharedPlugIn] startStream]; + + return kCMIOHardwareNoError; +} + +OSStatus HardwarePlugIn_DeviceSuspend(CMIOHardwarePlugInRef self, + CMIODeviceID deviceID) +{ + DLogFunc(@"self=%p", self); + return kCMIOHardwareNoError; +} + +OSStatus HardwarePlugIn_DeviceResume(CMIOHardwarePlugInRef self, + CMIODeviceID deviceID) +{ + DLogFunc(@"self=%p", self); + return kCMIOHardwareNoError; +} + +OSStatus HardwarePlugIn_DeviceStopStream(CMIOHardwarePlugInRef self, + CMIODeviceID deviceID, + CMIOStreamID streamID) +{ + DLogFunc(@"self=%p device=%d stream=%d", self, deviceID, streamID); + + OBSDALStream *stream = + (OBSDALStream *)[OBSDALObjectStore GetObjectWithId:streamID]; + + if (stream == nil) { + DLogFunc(@"ERR nil object"); + return kCMIOHardwareBadObjectError; + } + + [[OBSDALPlugin SharedPlugIn] stopStream]; + + return kCMIOHardwareNoError; +} + +OSStatus +HardwarePlugIn_DeviceProcessAVCCommand(CMIOHardwarePlugInRef self, + CMIODeviceID deviceID, + CMIODeviceAVCCommand *ioAVCCommand) +{ + DLogFunc(@"self=%p", self); + return kCMIOHardwareNoError; +} + +OSStatus +HardwarePlugIn_DeviceProcessRS422Command(CMIOHardwarePlugInRef self, + CMIODeviceID deviceID, + CMIODeviceRS422Command *ioRS422Command) +{ + DLogFunc(@"self=%p", self); + return kCMIOHardwareNoError; +} + +OSStatus HardwarePlugIn_StreamDeckPlay(CMIOHardwarePlugInRef self, + CMIOStreamID streamID) +{ + DLogFunc(@"self=%p", self); + return kCMIOHardwareIllegalOperationError; +} + +OSStatus HardwarePlugIn_StreamDeckStop(CMIOHardwarePlugInRef self, + CMIOStreamID streamID) +{ + DLogFunc(@"self=%p", self); + return kCMIOHardwareIllegalOperationError; +} + +OSStatus HardwarePlugIn_StreamDeckJog(CMIOHardwarePlugInRef self, + CMIOStreamID streamID, SInt32 speed) +{ + DLogFunc(@"self=%p", self); + return kCMIOHardwareIllegalOperationError; +} + +OSStatus HardwarePlugIn_StreamDeckCueTo(CMIOHardwarePlugInRef self, + CMIOStreamID streamID, + Float64 requestedTimecode, + Boolean playOnCue) +{ + DLogFunc(@"self=%p", self); + return kCMIOHardwareIllegalOperationError; +} + +static CMIOHardwarePlugInInterface sInterface = { + // Padding for COM + NULL, + + // IUnknown Routines + (HRESULT (*)(void *, CFUUIDBytes, + void **))HardwarePlugIn_QueryInterface, + (ULONG(*)(void *))HardwarePlugIn_AddRef, + (ULONG(*)(void *))HardwarePlugIn_Release, + + // DAL Plug-In Routines + HardwarePlugIn_Initialize, HardwarePlugIn_InitializeWithObjectID, + HardwarePlugIn_Teardown, HardwarePlugIn_ObjectShow, + HardwarePlugIn_ObjectHasProperty, + HardwarePlugIn_ObjectIsPropertySettable, + HardwarePlugIn_ObjectGetPropertyDataSize, + HardwarePlugIn_ObjectGetPropertyData, + HardwarePlugIn_ObjectSetPropertyData, HardwarePlugIn_DeviceSuspend, + HardwarePlugIn_DeviceResume, HardwarePlugIn_DeviceStartStream, + HardwarePlugIn_DeviceStopStream, HardwarePlugIn_DeviceProcessAVCCommand, + HardwarePlugIn_DeviceProcessRS422Command, + HardwarePlugIn_StreamCopyBufferQueue, HardwarePlugIn_StreamDeckPlay, + HardwarePlugIn_StreamDeckStop, HardwarePlugIn_StreamDeckJog, + HardwarePlugIn_StreamDeckCueTo}; + +static CMIOHardwarePlugInInterface *sInterfacePtr = &sInterface; +static CMIOHardwarePlugInRef sPlugInRef = &sInterfacePtr; + +CMIOHardwarePlugInRef OBSDALPlugInRef() +{ + return sPlugInRef; +} diff --git a/plugins/mac-virtualcam/src/dal-plugin/OBSDALPlugin.h b/plugins/mac-virtualcam/src/dal-plugin/OBSDALPlugin.h new file mode 100644 index 0000000..5ee4185 --- /dev/null +++ b/plugins/mac-virtualcam/src/dal-plugin/OBSDALPlugin.h @@ -0,0 +1,51 @@ +// +// PlugIn.h +// obs-mac-virtualcam +// +// Created by John Boiles on 4/9/20. +// +// obs-mac-virtualcam is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 2 of the License, or +// (at your option) any later version. +// +// obs-mac-virtualcam is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with obs-mac-virtualcam. If not, see . + +#import +#import + +#import "OBSDALObjectStore.h" +#import "OBSDALMachClient.h" +#import "OBSDALStream.h" + +#define kTestCardWidthKey @"obs-mac-virtualcam-test-card-width" +#define kTestCardHeightKey @"obs-mac-virtualcam-test-card-height" +#define kTestCardFPSKey @"obs-mac-virtualcam-test-card-fps" + +NS_ASSUME_NONNULL_BEGIN + +@interface OBSDALPlugin : NSObject + +@property CMIOObjectID objectId; +@property (readonly) OBSDALMachClient *machClient; +@property OBSDALStream *stream; + ++ (OBSDALPlugin *)SharedPlugIn; + +- (void)initialize; + +- (void)teardown; + +- (void)startStream; + +- (void)stopStream; + +@end + +NS_ASSUME_NONNULL_END diff --git a/plugins/mac-virtualcam/src/dal-plugin/OBSDALPlugin.mm b/plugins/mac-virtualcam/src/dal-plugin/OBSDALPlugin.mm new file mode 100644 index 0000000..242dbb5 --- /dev/null +++ b/plugins/mac-virtualcam/src/dal-plugin/OBSDALPlugin.mm @@ -0,0 +1,255 @@ +// +// PlugIn.mm +// obs-mac-virtualcam +// +// Created by John Boiles on 4/9/20. +// +// obs-mac-virtualcam is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 2 of the License, or +// (at your option) any later version. +// +// obs-mac-virtualcam is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with obs-mac-virtualcam. If not, see . + +#import "OBSDALPlugin.h" + +#import + +#import "Logging.h" + +typedef enum { + PlugInStateNotStarted = 0, + PlugInStateWaitingForServer, + PlugInStateReceivingFrames, +} OBSDALPlugInState; + +@interface OBSDALPlugin () { + //! Serial queue for all state changes that need to be concerned with thread safety + dispatch_queue_t _stateQueue; + + //! Repeated timer for driving the mach server re-connection + dispatch_source_t _machConnectTimer; + + //! Timeout timer when we haven't received frames for 5s + dispatch_source_t _timeoutTimer; +} +@property OBSDALPlugInState state; +@property OBSDALMachClient *machClient; + +@end + +@implementation OBSDALPlugin + ++ (OBSDALPlugin *)SharedPlugIn +{ + static OBSDALPlugin *sPlugIn = nil; + static dispatch_once_t sOnceToken; + dispatch_once(&sOnceToken, ^{ + sPlugIn = [[self alloc] init]; + }); + return sPlugIn; +} + +- (instancetype)init +{ + if (self = [super init]) { + _stateQueue = dispatch_queue_create( + "com.obsproject.obs-mac-virtualcam.dal.state", + DISPATCH_QUEUE_SERIAL); + + _timeoutTimer = dispatch_source_create( + DISPATCH_SOURCE_TYPE_TIMER, 0, 0, _stateQueue); + __weak __typeof(self) weakSelf = self; + dispatch_source_set_event_handler(_timeoutTimer, ^{ + if (weakSelf.state == PlugInStateReceivingFrames) { + DLog(@"No frames received for 5s, restarting connection"); + [self stopStream]; + [self startStream]; + } + }); + + _machClient = [[OBSDALMachClient alloc] init]; + _machClient.delegate = self; + + _machConnectTimer = dispatch_source_create( + DISPATCH_SOURCE_TYPE_TIMER, 0, 0, _stateQueue); + dispatch_time_t startTime = dispatch_time(DISPATCH_TIME_NOW, 0); + uint64_t intervalTime = (int64_t)(1 * NSEC_PER_SEC); + dispatch_source_set_timer(_machConnectTimer, startTime, + intervalTime, 0); + dispatch_source_set_event_handler(_machConnectTimer, ^{ + if (![[weakSelf machClient] isServerAvailable]) { + DLog(@"Server is not available"); + } else if (weakSelf.state == + PlugInStateWaitingForServer) { + DLog(@"Attempting connection"); + [[weakSelf machClient] connectToServer]; + } + }); + } + return self; +} + +- (void)startStream +{ + DLogFunc(@""); + dispatch_async(_stateQueue, ^{ + if (_state == PlugInStateNotStarted) { + dispatch_resume(_machConnectTimer); + [self.stream startServingDefaultFrames]; + _state = PlugInStateWaitingForServer; + } + }); +} + +- (void)stopStream +{ + DLogFunc(@""); + dispatch_async(_stateQueue, ^{ + if (_state == PlugInStateWaitingForServer) { + dispatch_suspend(_machConnectTimer); + [self.stream stopServingDefaultFrames]; + } else if (_state == PlugInStateReceivingFrames) { + // TODO: Disconnect from the mach server? + dispatch_suspend(_timeoutTimer); + } + _state = PlugInStateNotStarted; + }); +} + +- (void)initialize +{ +} + +- (void)teardown +{ +} + +#pragma mark - CMIOObject + +- (BOOL)hasPropertyWithAddress:(CMIOObjectPropertyAddress)address +{ + switch (address.mSelector) { + case kCMIOObjectPropertyName: + return true; + default: + DLog(@"PlugIn unhandled hasPropertyWithAddress for %@", + [OBSDALObjectStore + StringFromPropertySelector:address.mSelector]); + return false; + }; +} + +- (BOOL)isPropertySettableWithAddress:(CMIOObjectPropertyAddress)address +{ + switch (address.mSelector) { + case kCMIOObjectPropertyName: + return false; + default: + DLog(@"PlugIn unhandled isPropertySettableWithAddress for %@", + [OBSDALObjectStore + StringFromPropertySelector:address.mSelector]); + return false; + }; +} + +- (UInt32)getPropertyDataSizeWithAddress:(CMIOObjectPropertyAddress)address + qualifierDataSize:(UInt32)qualifierDataSize + qualifierData:(const void *)qualifierData +{ + switch (address.mSelector) { + case kCMIOObjectPropertyName: + return sizeof(CFStringRef); + default: + DLog(@"PlugIn unhandled getPropertyDataSizeWithAddress for %@", + [OBSDALObjectStore + StringFromPropertySelector:address.mSelector]); + return 0; + }; +} + +- (void)getPropertyDataWithAddress:(CMIOObjectPropertyAddress)address + qualifierDataSize:(UInt32)qualifierDataSize + qualifierData:(nonnull const void *)qualifierData + dataSize:(UInt32)dataSize + dataUsed:(nonnull UInt32 *)dataUsed + data:(nonnull void *)data +{ + switch (address.mSelector) { + case kCMIOObjectPropertyName: + *static_cast(data) = + CFSTR("OBS Virtual Camera Plugin"); + *dataUsed = sizeof(CFStringRef); + return; + default: + DLog(@"PlugIn unhandled getPropertyDataWithAddress for %@", + [OBSDALObjectStore + StringFromPropertySelector:address.mSelector]); + return; + }; +} + +- (void)setPropertyDataWithAddress:(CMIOObjectPropertyAddress)address + qualifierDataSize:(UInt32)qualifierDataSize + qualifierData:(nonnull const void *)qualifierData + dataSize:(UInt32)dataSize + data:(nonnull const void *)data +{ + DLog(@"PlugIn unhandled setPropertyDataWithAddress for %@", + [OBSDALObjectStore StringFromPropertySelector:address.mSelector]); +} + +#pragma mark - MachClientDelegate + +- (void)receivedFrameWithSize:(NSSize)size + timestamp:(uint64_t)timestamp + fpsNumerator:(uint32_t)fpsNumerator + fpsDenominator:(uint32_t)fpsDenominator + frameData:(NSData *)frameData +{ + dispatch_sync(_stateQueue, ^{ + if (_state == PlugInStateWaitingForServer) { + NSUserDefaults *defaults = + [NSUserDefaults standardUserDefaults]; + [defaults setInteger:size.width + forKey:kTestCardWidthKey]; + [defaults setInteger:size.height + forKey:kTestCardHeightKey]; + [defaults setDouble:(double)fpsNumerator / + (double)fpsDenominator + forKey:kTestCardFPSKey]; + + dispatch_suspend(_machConnectTimer); + [self.stream stopServingDefaultFrames]; + dispatch_resume(_timeoutTimer); + _state = PlugInStateReceivingFrames; + } + }); + + // Add 5 more seconds onto the timeout timer + dispatch_source_set_timer( + _timeoutTimer, + dispatch_time(DISPATCH_TIME_NOW, 5.0 * NSEC_PER_SEC), + 5.0 * NSEC_PER_SEC, (1ull * NSEC_PER_SEC) / 10); + + [self.stream queueFrameWithSize:size + timestamp:timestamp + fpsNumerator:fpsNumerator + fpsDenominator:fpsDenominator + frameData:frameData]; +} + +- (void)receivedStop +{ + DLogFunc(@"Restarting connection"); + [self stopStream]; + [self startStream]; +} + +@end diff --git a/plugins/mac-virtualcam/src/dal-plugin/OBSDALPluginMain.mm b/plugins/mac-virtualcam/src/dal-plugin/OBSDALPluginMain.mm new file mode 100644 index 0000000..711cef9 --- /dev/null +++ b/plugins/mac-virtualcam/src/dal-plugin/OBSDALPluginMain.mm @@ -0,0 +1,37 @@ +// +// PlugInMain.mm +// obs-mac-virtualcam +// +// Created by John Boiles on 4/9/20. +// +// obs-mac-virtualcam is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 2 of the License, or +// (at your option) any later version. +// +// obs-mac-virtualcam is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with obs-mac-virtualcam. If not, see . + +#import + +#import "OBSDALPlugInInterface.h" +#import "Logging.h" +#import "Defines.h" + +//! PlugInMain is the entrypoint for the plugin +extern "C" { +void *PlugInMain(CFAllocatorRef allocator, CFUUIDRef requestedTypeUUID) +{ + DLogFunc(@"version=%@", PLUGIN_VERSION); + if (!CFEqual(requestedTypeUUID, kCMIOHardwarePlugInTypeID)) { + return 0; + } + + return OBSDALPlugInRef(); +} +} diff --git a/plugins/mac-virtualcam/src/dal-plugin/OBSDALStream.h b/plugins/mac-virtualcam/src/dal-plugin/OBSDALStream.h new file mode 100644 index 0000000..703e0c2 --- /dev/null +++ b/plugins/mac-virtualcam/src/dal-plugin/OBSDALStream.h @@ -0,0 +1,48 @@ +// +// Stream.h +// obs-mac-virtualcam +// +// Created by John Boiles on 4/10/20. +// +// obs-mac-virtualcam is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 2 of the License, or +// (at your option) any later version. +// +// obs-mac-virtualcam is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with obs-mac-virtualcam. If not, see . + +#import + +#import "OBSDALObjectStore.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface OBSDALStream : NSObject + +@property CMIOStreamID objectId; + +- (instancetype _Nonnull)init; + +- (CMSimpleQueueRef)copyBufferQueueWithAlteredProc: + (CMIODeviceStreamQueueAlteredProc)alteredProc + alteredRefCon:(void *)alteredRefCon; + +- (void)startServingDefaultFrames; + +- (void)stopServingDefaultFrames; + +- (void)queueFrameWithSize:(NSSize)size + timestamp:(uint64_t)timestamp + fpsNumerator:(uint32_t)fpsNumerator + fpsDenominator:(uint32_t)fpsDenominator + frameData:(NSData *)frameData; + +@end + +NS_ASSUME_NONNULL_END diff --git a/plugins/mac-virtualcam/src/dal-plugin/OBSDALStream.mm b/plugins/mac-virtualcam/src/dal-plugin/OBSDALStream.mm new file mode 100644 index 0000000..c69938f --- /dev/null +++ b/plugins/mac-virtualcam/src/dal-plugin/OBSDALStream.mm @@ -0,0 +1,570 @@ +// +// Stream.mm +// obs-mac-virtualcam +// +// Created by John Boiles on 4/10/20. +// +// obs-mac-virtualcam is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 2 of the License, or +// (at your option) any later version. +// +// obs-mac-virtualcam is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with obs-mac-virtualcam. If not, see . + +#import "OBSDALStream.h" + +#import +#import +#include + +#import "Logging.h" +#import "CMSampleBufferUtils.h" +#import "OBSDALPlugin.h" + +@interface OBSDALStream () { + CMSimpleQueueRef _queue; + CFTypeRef _clock; + NSImage *_testCardImage; + dispatch_source_t _frameDispatchSource; + NSSize _testCardSize; + Float64 _fps; +} + +@property CMIODeviceStreamQueueAlteredProc alteredProc; +@property void *alteredRefCon; +@property (readonly) CMSimpleQueueRef queue; +@property (readonly) CFTypeRef clock; +@property UInt64 sequenceNumber; +@property (readonly) NSImage *testCardImage; +@property (readonly) NSSize testCardSize; +@property (readonly) Float64 fps; + +@end + +@implementation OBSDALStream + +#define DEFAULT_FPS 30.0 +#define DEFAULT_WIDTH 1280 +#define DEFAULT_HEIGHT 720 + +- (instancetype _Nonnull)init +{ + self = [super init]; + if (self) { + _frameDispatchSource = dispatch_source_create( + DISPATCH_SOURCE_TYPE_TIMER, 0, 0, + dispatch_get_global_queue( + DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)); + __weak __typeof(self) wself = self; + dispatch_source_set_event_handler(_frameDispatchSource, ^{ + [wself fillFrame]; + }); + } + return self; +} + +- (void)dealloc +{ + DLog(@"Stream Dealloc"); + CMIOStreamClockInvalidate(_clock); + CFRelease(_clock); + _clock = NULL; + CFRelease(_queue); + _queue = NULL; + dispatch_suspend(_frameDispatchSource); +} + +- (void)startServingDefaultFrames +{ + DLogFunc(@""); + _testCardImage = nil; + _testCardSize = NSZeroSize; + _fps = 0; + dispatch_time_t startTime = dispatch_time(DISPATCH_TIME_NOW, 0); + uint64_t intervalTime = (int64_t)(NSEC_PER_SEC / self.fps); + dispatch_source_set_timer(_frameDispatchSource, startTime, intervalTime, + 0); + dispatch_resume(_frameDispatchSource); +} + +- (void)stopServingDefaultFrames +{ + DLogFunc(@""); + dispatch_suspend(_frameDispatchSource); +} + +- (CMSimpleQueueRef)queue +{ + if (_queue == NULL) { + // Allocate a one-second long queue, which we can use our FPS constant for. + OSStatus err = CMSimpleQueueCreate(kCFAllocatorDefault, + self.fps, &_queue); + if (err != noErr) { + DLog(@"Err %d in CMSimpleQueueCreate", err); + } + } + return _queue; +} + +- (CFTypeRef)clock +{ + if (_clock == NULL) { + OSStatus err = CMIOStreamClockCreate( + kCFAllocatorDefault, + CFSTR("obs-mac-virtualcam::Stream::clock"), + (__bridge void *)self, CMTimeMake(1, 10), 100, 10, + &_clock); + if (err != noErr) { + DLog(@"Error %d from CMIOStreamClockCreate", err); + } + } + return _clock; +} + +- (NSSize)testCardSize +{ + if (NSEqualSizes(_testCardSize, NSZeroSize)) { + NSUserDefaults *defaults = + [NSUserDefaults standardUserDefaults]; + int width = [[defaults objectForKey:kTestCardWidthKey] + integerValue]; + int height = [[defaults objectForKey:kTestCardHeightKey] + integerValue]; + if (width == 0 || height == 0) { + _testCardSize = + NSMakeSize(DEFAULT_WIDTH, DEFAULT_HEIGHT); + } else { + _testCardSize = NSMakeSize(width, height); + } + } + return _testCardSize; +} + +- (Float64)fps +{ + if (_fps == 0) { + NSUserDefaults *defaults = + [NSUserDefaults standardUserDefaults]; + double fps = + [[defaults objectForKey:kTestCardFPSKey] doubleValue]; + if (fps == 0) { + _fps = DEFAULT_FPS; + } else { + _fps = fps; + } + } + return _fps; +} + +- (NSImage *)testCardImage +{ + if (_testCardImage == nil) { + NSString *bundlePath = [[NSBundle + bundleForClass:[OBSDALStream class]] bundlePath]; + NSString *placeHolderPath = [bundlePath + stringByAppendingString: + @"/Contents/Resources/placeholder.png"]; + NSImage *placeholderImage = [[NSImage alloc] + initWithContentsOfFile:placeHolderPath]; + + NSBitmapImageRep *rep = [[NSBitmapImageRep alloc] + initWithBitmapDataPlanes:NULL + pixelsWide:self.testCardSize.width + pixelsHigh:self.testCardSize.height + bitsPerSample:8 + samplesPerPixel:4 + hasAlpha:YES + isPlanar:NO + colorSpaceName:NSCalibratedRGBColorSpace + bytesPerRow:0 + bitsPerPixel:0]; + rep.size = self.testCardSize; + + float hScale = + placeholderImage.size.width / self.testCardSize.width; + float vScale = + placeholderImage.size.height / self.testCardSize.height; + + float scaling = fmax(hScale, vScale); + + float newWidth = placeholderImage.size.width / scaling; + float newHeight = placeholderImage.size.height / scaling; + + float leftOffset = (self.testCardSize.width - newWidth) / 2; + float topOffset = (self.testCardSize.height - newHeight) / 2; + + [NSGraphicsContext saveGraphicsState]; + [NSGraphicsContext + setCurrentContext: + [NSGraphicsContext + graphicsContextWithBitmapImageRep:rep]]; + + NSColor *backgroundColor = [NSColor blackColor]; + [backgroundColor set]; + NSRectFill(NSMakeRect(0, 0, self.testCardSize.width, + self.testCardSize.height)); + + [placeholderImage drawInRect:NSMakeRect(leftOffset, topOffset, + newWidth, newHeight) + fromRect:NSZeroRect + operation:NSCompositingOperationCopy + fraction:1.0]; + [NSGraphicsContext restoreGraphicsState]; + + NSImage *testCardImage = + [[NSImage alloc] initWithSize:self.testCardSize]; + [testCardImage addRepresentation:rep]; + + _testCardImage = testCardImage; + } + return _testCardImage; +} + +- (CMSimpleQueueRef)copyBufferQueueWithAlteredProc: + (CMIODeviceStreamQueueAlteredProc)alteredProc + alteredRefCon:(void *)alteredRefCon +{ + self.alteredProc = alteredProc; + self.alteredRefCon = alteredRefCon; + + // Retain this since it's a copy operation + CFRetain(self.queue); + + return self.queue; +} + +- (CVPixelBufferRef)createPixelBufferWithTestAnimation +{ + int width = self.testCardSize.width; + int height = self.testCardSize.height; + + NSDictionary *options = [NSDictionary + dictionaryWithObjectsAndKeys: + [NSNumber numberWithBool:YES], + kCVPixelBufferCGImageCompatibilityKey, + [NSNumber numberWithBool:YES], + kCVPixelBufferCGBitmapContextCompatibilityKey, nil]; + CVPixelBufferRef pxbuffer = NULL; + CVReturn status = CVPixelBufferCreate(kCFAllocatorDefault, width, + height, kCVPixelFormatType_32ARGB, + (__bridge CFDictionaryRef)options, + &pxbuffer); + + NSParameterAssert(status == kCVReturnSuccess && pxbuffer != NULL); + + CVPixelBufferLockBaseAddress(pxbuffer, 0); + void *pxdata = CVPixelBufferGetBaseAddressOfPlane(pxbuffer, 0); + NSParameterAssert(pxdata != NULL); + + CGColorSpaceRef rgbColorSpace = CGColorSpaceCreateDeviceRGB(); + CGContextRef context = CGBitmapContextCreate( + pxdata, width, height, 8, + CVPixelBufferGetBytesPerRowOfPlane(pxbuffer, 0), rgbColorSpace, + kCGImageAlphaPremultipliedFirst | kCGImageByteOrder32Big); + NSParameterAssert(context); + + NSGraphicsContext *nsContext = [NSGraphicsContext + graphicsContextWithCGContext:context + flipped:NO]; + [NSGraphicsContext setCurrentContext:nsContext]; + + NSRect rect = NSMakeRect(0, 0, self.testCardImage.size.width, + self.testCardImage.size.height); + CGImageRef image = [self.testCardImage CGImageForProposedRect:&rect + context:nsContext + hints:nil]; + CGContextDrawImage(context, + CGRectMake(0, 0, CGImageGetWidth(image), + CGImageGetHeight(image)), + image); + + // DrawDialWithFrame( + // NSMakeRect(0, 0, width, height), + // (int(self.fps) - self.sequenceNumber % int(self.fps)) * 360 / + // int(self.fps)); + + CGContextRelease(context); + + CVPixelBufferUnlockBaseAddress(pxbuffer, 0); + + return pxbuffer; +} + +- (void)fillFrame +{ + if (CMSimpleQueueGetFullness(self.queue) >= 1.0) { + DLog(@"Queue is full, bailing out"); + return; + } + + CVPixelBufferRef pixelBuffer = + [self createPixelBufferWithTestAnimation]; + + uint64_t hostTime = mach_absolute_time(); + CMSampleTimingInfo timingInfo = + CMSampleTimingInfoForTimestamp(hostTime, self.fps, 1); + + OSStatus err = CMIOStreamClockPostTimingEvent( + timingInfo.presentationTimeStamp, hostTime, true, self.clock); + if (err != noErr) { + DLog(@"CMIOStreamClockPostTimingEvent err %d", err); + } + + CMFormatDescriptionRef format; + CMVideoFormatDescriptionCreateForImageBuffer(kCFAllocatorDefault, + pixelBuffer, &format); + + self.sequenceNumber = CMIOGetNextSequenceNumber(self.sequenceNumber); + + CMSampleBufferRef buffer; + err = CMIOSampleBufferCreateForImageBuffer( + kCFAllocatorDefault, pixelBuffer, format, &timingInfo, + self.sequenceNumber, kCMIOSampleBufferNoDiscontinuities, + &buffer); + CFRelease(pixelBuffer); + CFRelease(format); + if (err != noErr) { + DLog(@"CMIOSampleBufferCreateForImageBuffer err %d", err); + } + + CMSimpleQueueEnqueue(self.queue, buffer); + + // Inform the clients that the queue has been altered + if (self.alteredProc != NULL) { + (self.alteredProc)(self.objectId, buffer, self.alteredRefCon); + } +} + +- (void)queueFrameWithSize:(NSSize)size + timestamp:(uint64_t)timestamp + fpsNumerator:(uint32_t)fpsNumerator + fpsDenominator:(uint32_t)fpsDenominator + frameData:(NSData *)frameData +{ + if (CMSimpleQueueGetFullness(self.queue) >= 1.0) { + DLog(@"Queue is full, bailing out"); + return; + } + OSStatus err = noErr; + + CMSampleTimingInfo timingInfo = CMSampleTimingInfoForTimestamp( + timestamp, fpsNumerator, fpsDenominator); + + err = CMIOStreamClockPostTimingEvent(timingInfo.presentationTimeStamp, + mach_absolute_time(), true, + self.clock); + if (err != noErr) { + DLog(@"CMIOStreamClockPostTimingEvent err %d", err); + } + + self.sequenceNumber = CMIOGetNextSequenceNumber(self.sequenceNumber); + + CMSampleBufferRef sampleBuffer; + CMSampleBufferCreateFromData(size, timingInfo, self.sequenceNumber, + frameData, &sampleBuffer); + CMSimpleQueueEnqueue(self.queue, sampleBuffer); + + // Inform the clients that the queue has been altered + if (self.alteredProc != NULL) { + (self.alteredProc)(self.objectId, sampleBuffer, + self.alteredRefCon); + } +} + +- (CMVideoFormatDescriptionRef)getFormatDescription +{ + CMVideoFormatDescriptionRef formatDescription; + OSStatus err = CMVideoFormatDescriptionCreate( + kCFAllocatorDefault, kCMVideoCodecType_422YpCbCr8, + self.testCardSize.width, self.testCardSize.height, NULL, + &formatDescription); + if (err != noErr) { + DLog(@"Error %d from CMVideoFormatDescriptionCreate", err); + } + return formatDescription; +} + +#pragma mark - CMIOObject + +- (UInt32)getPropertyDataSizeWithAddress:(CMIOObjectPropertyAddress)address + qualifierDataSize:(UInt32)qualifierDataSize + qualifierData:(nonnull const void *)qualifierData +{ + switch (address.mSelector) { + case kCMIOStreamPropertyInitialPresentationTimeStampForLinkedAndSyncedAudio: + return sizeof(CMTime); + case kCMIOStreamPropertyOutputBuffersNeededForThrottledPlayback: + return sizeof(UInt32); + case kCMIOObjectPropertyName: + return sizeof(CFStringRef); + case kCMIOObjectPropertyManufacturer: + return sizeof(CFStringRef); + case kCMIOObjectPropertyElementName: + return sizeof(CFStringRef); + case kCMIOObjectPropertyElementCategoryName: + return sizeof(CFStringRef); + case kCMIOObjectPropertyElementNumberName: + return sizeof(CFStringRef); + case kCMIOStreamPropertyDirection: + return sizeof(UInt32); + case kCMIOStreamPropertyTerminalType: + return sizeof(UInt32); + case kCMIOStreamPropertyStartingChannel: + return sizeof(UInt32); + case kCMIOStreamPropertyLatency: + return sizeof(UInt32); + case kCMIOStreamPropertyFormatDescriptions: + return sizeof(CFArrayRef); + case kCMIOStreamPropertyFormatDescription: + return sizeof(CMFormatDescriptionRef); + case kCMIOStreamPropertyFrameRateRanges: + return sizeof(AudioValueRange); + case kCMIOStreamPropertyFrameRate: + case kCMIOStreamPropertyFrameRates: + return sizeof(Float64); + case kCMIOStreamPropertyMinimumFrameRate: + return sizeof(Float64); + case kCMIOStreamPropertyClock: + return sizeof(CFTypeRef); + default: + DLog(@"Stream unhandled getPropertyDataSizeWithAddress for %@", + [OBSDALObjectStore + StringFromPropertySelector:address.mSelector]); + return 0; + }; +} + +- (void)getPropertyDataWithAddress:(CMIOObjectPropertyAddress)address + qualifierDataSize:(UInt32)qualifierDataSize + qualifierData:(nonnull const void *)qualifierData + dataSize:(UInt32)dataSize + dataUsed:(nonnull UInt32 *)dataUsed + data:(nonnull void *)data +{ + switch (address.mSelector) { + case kCMIOObjectPropertyName: + *static_cast(data) = CFSTR("OBS Virtual Camera"); + *dataUsed = sizeof(CFStringRef); + break; + case kCMIOObjectPropertyElementName: + *static_cast(data) = + CFSTR("OBS Virtual Camera Stream Element"); + *dataUsed = sizeof(CFStringRef); + break; + case kCMIOObjectPropertyManufacturer: + case kCMIOObjectPropertyElementCategoryName: + case kCMIOObjectPropertyElementNumberName: + case kCMIOStreamPropertyTerminalType: + case kCMIOStreamPropertyStartingChannel: + case kCMIOStreamPropertyLatency: + case kCMIOStreamPropertyInitialPresentationTimeStampForLinkedAndSyncedAudio: + case kCMIOStreamPropertyOutputBuffersNeededForThrottledPlayback: + break; + case kCMIOStreamPropertyDirection: + *static_cast(data) = 1; + *dataUsed = sizeof(UInt32); + break; + case kCMIOStreamPropertyFormatDescriptions: + *static_cast( + data) = (__bridge_retained CFArrayRef)[NSArray + arrayWithObject:(__bridge_transfer NSObject *) + [self getFormatDescription]]; + *dataUsed = sizeof(CFArrayRef); + break; + case kCMIOStreamPropertyFormatDescription: + *static_cast(data) = + [self getFormatDescription]; + *dataUsed = sizeof(CMVideoFormatDescriptionRef); + break; + case kCMIOStreamPropertyFrameRateRanges: + AudioValueRange range; + range.mMinimum = self.fps; + range.mMaximum = self.fps; + *static_cast(data) = range; + *dataUsed = sizeof(AudioValueRange); + break; + case kCMIOStreamPropertyFrameRate: + case kCMIOStreamPropertyFrameRates: + *static_cast(data) = self.fps; + *dataUsed = sizeof(Float64); + break; + case kCMIOStreamPropertyMinimumFrameRate: + *static_cast(data) = self.fps; + *dataUsed = sizeof(Float64); + break; + case kCMIOStreamPropertyClock: + *static_cast(data) = self.clock; + // This one was incredibly tricky and cost me many hours to find. It seems that DAL expects + // the clock to be retained when returned. It's unclear why, and that seems inconsistent + // with other properties that don't have the same behavior. But this is what Apple's sample + // code does. + // https://github.com/lvsti/CoreMediaIO-DAL-Example/blob/0392cb/Sources/Extras/CoreMediaIO/DeviceAbstractionLayer/Devices/DP/Properties/CMIO_DP_Property_Clock.cpp#L75 + CFRetain(*static_cast(data)); + *dataUsed = sizeof(CFTypeRef); + break; + default: + DLog(@"Stream unhandled getPropertyDataWithAddress for %@", + [OBSDALObjectStore + StringFromPropertySelector:address.mSelector]); + *dataUsed = 0; + }; +} + +- (BOOL)hasPropertyWithAddress:(CMIOObjectPropertyAddress)address +{ + switch (address.mSelector) { + case kCMIOObjectPropertyName: + case kCMIOObjectPropertyElementName: + case kCMIOStreamPropertyFormatDescriptions: + case kCMIOStreamPropertyFormatDescription: + case kCMIOStreamPropertyFrameRateRanges: + case kCMIOStreamPropertyFrameRate: + case kCMIOStreamPropertyFrameRates: + case kCMIOStreamPropertyMinimumFrameRate: + case kCMIOStreamPropertyClock: + return true; + case kCMIOObjectPropertyManufacturer: + case kCMIOObjectPropertyElementCategoryName: + case kCMIOObjectPropertyElementNumberName: + case kCMIOStreamPropertyDirection: + case kCMIOStreamPropertyTerminalType: + case kCMIOStreamPropertyStartingChannel: + case kCMIOStreamPropertyLatency: + case kCMIOStreamPropertyInitialPresentationTimeStampForLinkedAndSyncedAudio: + case kCMIOStreamPropertyOutputBuffersNeededForThrottledPlayback: + DLog(@"TODO: %@", + [OBSDALObjectStore + StringFromPropertySelector:address.mSelector]); + return false; + default: + DLog(@"Stream unhandled hasPropertyWithAddress for %@", + [OBSDALObjectStore + StringFromPropertySelector:address.mSelector]); + return false; + }; +} + +- (BOOL)isPropertySettableWithAddress:(CMIOObjectPropertyAddress)address +{ + DLog(@"Stream unhandled isPropertySettableWithAddress for %@", + [OBSDALObjectStore StringFromPropertySelector:address.mSelector]); + return false; +} + +- (void)setPropertyDataWithAddress:(CMIOObjectPropertyAddress)address + qualifierDataSize:(UInt32)qualifierDataSize + qualifierData:(nonnull const void *)qualifierData + dataSize:(UInt32)dataSize + data:(nonnull const void *)data +{ + DLog(@"Stream unhandled setPropertyDataWithAddress for %@", + [OBSDALObjectStore StringFromPropertySelector:address.mSelector]); +} + +@end diff --git a/plugins/mac-virtualcam/src/dal-plugin/placeholder.png b/plugins/mac-virtualcam/src/dal-plugin/placeholder.png new file mode 100644 index 0000000000000000000000000000000000000000..70721300311cd30610ede698e13acb74fcedab4f GIT binary patch literal 314050 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 z zi)BfYa$}p0K0|e~m8>?1!Jl?3nLw6Y&uo-8tBWpMGR6n|eIw3?lsi45$~mD8e#SSn zFf5I=T0CI(HD2BOjQDS+F!Yw8w6iNP+qGY5@q0dPd4D>v)L-{MUb4)69hSyitH0d8 zJzl_7Gpe(b9q11eC*cpU#-P!GtXk$$pyC^wpf!SBXWc$$UM|=B{6;>vJMm&K zN0l4_Z;zJSJ3W*l3g0u6N`$AVm|yRX^%so&{k9qfbu;K3rpqx;h{0 z6vI@9Xz|=HHIk@)TS_>oLI@AD?NipUAPZLfqYWUfuR<+^C66|U^VuTv@Qz&}{2ZM_ zJQc%^yulyJP*8Soj8XR&ON8oaphEY-hm@+##@CfhnQMtmMfP%XuXJIX+Nw4>-FpBI z|Fp5#@jH{N7e39OvzIhWz23zSy_b-N_?l_e#qAAdGI9;bwo8Vv+RDY$7mDNPdbXf@ z>3xxikE+g@9079|^$1NY6f2F7jl+|tr$x?n0q<|8!p#BKlZ%x84_ho8T{j~o$}J9^ zUTgRPP+X0!zQ0_tT)$oaV*Qv*uR_9YGf_)D5J_)oX$DPt^RL-R+rKXI7G=t5OlfS~ zZJaYZ@L1lQYur^RQU?WyGEF&h_~j{_Vl#miP-`SuawF!nmLr#`U-{>cm9L9^UV?7E zTX05?@aEfZ&*2U!rwe)6IGdEYd>wpgyH3mPcu7L#$bUJ0KJU7RK4R9}-Np}c-@~~| zB1`%Cc$*pFE_q!2pG*y@TL z-S;EKn%uaPq|P@5m9|5t*&I=yp69n`Rk1h7UYgOh?rg^u)&_T;w z-i-SA@LdeLso!U}xP&U?S*b}WNhc~L3ZK8k<(U+WiiLkDMe+^$?oCB2n!YuiH-cuS zVHR5W?8?c_O{9zSnDuMk)XOZt8`pKzp8ip@B!UAdC*!&VX2H{sk~x@ z8qzEA-x8+xOqV*;5<;zsiZbI`tJ8`m(gpk0<2d0QucJ|qjisx-G-JDs?$_Qv>0w62 z_O4gpMB>}wFr^M#S8KbkuAH2tcb?K(dz9pV@Xuk*ACpm7EmM$hORg;fNm(027B(P=ATYK5frG$*H3d09j+M$()&S(V3F@3k5RAsL;;*9Cr&tz;djKiYxW{G2FhUL$lMY=c zhS|8WE1DTGlzc0jx`H8Z$ls`vFiS?D@b+jf6CLkEXBL%?L_!i4rS*1$P>QL$$P2c|nFeUW0yQgYV5 z;;lv|H}yWF?pN%SH>LL|4~TsH=Hd5yWcb+-FwhPut#qbEp~NvUB`YcGio6U}nW*4)3nn(B{f0j+u;e34K@p3#CiCfyNi`aQ=Tqsq)8 zjPU^M*D5$QAg3jVw-tGHO%I7zjZg$osd(UmOhJf>RO6XRy0gk$7pGqwOD2Kg)|DJr zp<;PQ4TO8D@PCa|ke>ihzLg9Dzf_xGX!QP{my?}o6(q>&{L+$aKZ&wD1{BAJ=W#R9 zioecj@~?T~62H!CFXB%y67gGzMCxEA-{Kg#UqxtYCTogr0WE&C%DCX~;_r^bsg^N8 zISrwG4nC;&z5W-I_@N& zD4xRXNH7TFj7YFr`5g*$3Ee5%*H1slO&2#>rPXj15Qs9K7(rH9%4OMQ3m$j8s7?8E zmJuJma|_+{PZ-X@uy%hWJdSWZ2$zx;NDtW=^1cG-NOZz}|C?tCYl>@?5E3B2?t@^4 z!wy)gQ^ZtC3O-i49upuSY|=>a4t{{~p(y+Q4IlZtb0jD`e9c-`a4GcKHWjKW>O(P@ zu#garo>Ad(KoPxjZTVrE{rl@lgDStHf7VP^8k;U(hc7|K1Ge4d=ma&1VoHXUos1A| z%x|V9K?rE2)!C$=_k}maStvH}8bP~&$L}7<93D~DxTxw)_0dk$c~u4{$%xYfraW=g z=U!C5#o_fW{5$|UkbHA>)wh%ym-9%fAG_QS@Vlz%F?Knf``l!G7%J*$-E|&r#y#SZ zAYfmXA_UWu5!lg+_DCCdf*JiXcIQ(Ujqn|#bA`5Cg`QF^jYyoO+!>29yTO|LpR9-a z1=^%jmE+lidfr)L@80)wboq8<*x8KYG4W3Z`jM9m*WUsgu?>FMDSuRD%^s(8$91 zC52=6psyyDWzI7nbG;ZD5_U3)p+)vYP{?0+9{$@4WzOo;8Om$VNzhM%r&nYb39{U+ zNs3T4<1w|0<$eXoG;h!2p^u-TUk>+L5Q3Mf7ROOYogT=T_t-}+NE__Kda$JZQh*Q*WF2CldBiX;SSX(`H?oRPo;*9OYes7Y$CcNwu z)4;RQhG8Da}Ux~_xTRX!s99ilDH4bOy zgvL*x5KRA@EhO>xm)SSz*vV>pWEK#3eyQoaWuvA0b{*>DB2dc6-5p&dMJ>x%SODw6 zQ}M#D20ue#(tz}u@?+tnw`F=_ky5^R!&68ghT;IpZl>}39?ifOATjQSqMj3{Y?W}n zwrx&V2-y6&{E>(?OQ-3m9i8+Y8in&$CibtyZ+-pyQ}K&akB#oDvGI>JbvBP77Ve=I;si z6e4f{lJl7SrHGe9`F#UEBTQ<%0DwJ4=QFmBD9Ta}GtZ@BZ;~N`9tLc;`-KqE)&7YA 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

M!G9stD#tXYGG%qa~5An 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

$(N`8LqA-*aPFOX8>dj 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 DS?I. + +#define PLUGIN_NAME "mac-virtualcam" +#define PLUGIN_VERSION "1.3.0" + +#define blog(level, msg, ...) \ + blog(level, "[" PLUGIN_NAME "] " msg, ##__VA_ARGS__) diff --git a/plugins/mac-virtualcam/src/obs-plugin/OBSDALMachServer.h b/plugins/mac-virtualcam/src/obs-plugin/OBSDALMachServer.h new file mode 100644 index 0000000..c6ab030 --- /dev/null +++ b/plugins/mac-virtualcam/src/obs-plugin/OBSDALMachServer.h @@ -0,0 +1,29 @@ +// +// MachServer.h +// obs-mac-virtualcam +// +// Created by John Boiles on 5/5/20. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface OBSDALMachServer : NSObject + +- (void)run; + +/*! + Will eventually be used for sending frames to all connected clients + */ +- (void)sendFrameWithSize:(NSSize)size + timestamp:(uint64_t)timestamp + fpsNumerator:(uint32_t)fpsNumerator + fpsDenominator:(uint32_t)fpsDenominator + frameBytes:(uint8_t *)frameBytes; + +- (void)stop; + +@end + +NS_ASSUME_NONNULL_END diff --git a/plugins/mac-virtualcam/src/obs-plugin/OBSDALMachServer.mm b/plugins/mac-virtualcam/src/obs-plugin/OBSDALMachServer.mm new file mode 100644 index 0000000..42db688 --- /dev/null +++ b/plugins/mac-virtualcam/src/obs-plugin/OBSDALMachServer.mm @@ -0,0 +1,178 @@ +// +// MachServer.m +// mac-virtualcam +// +// Created by John Boiles on 5/5/20. +// + +#import "OBSDALMachServer.h" +#import +#include +#include "MachProtocol.h" +#include "Defines.h" + +@interface OBSDALMachServer () +@property NSPort *port; +@property NSMutableSet *clientPorts; +@property NSRunLoop *runLoop; +@end + +@implementation OBSDALMachServer + +- (id)init +{ + if (self = [super init]) { + self.clientPorts = [[NSMutableSet alloc] init]; + } + return self; +} + +- (void)dealloc +{ + blog(LOG_DEBUG, "tearing down MachServer"); + [self.runLoop removePort:self.port forMode:NSDefaultRunLoopMode]; + [self.port invalidate]; + self.port.delegate = nil; +} + +- (void)run +{ + if (self.port != nil) { + blog(LOG_DEBUG, "mach server already running!"); + return; + } + +// It's a bummer this is deprecated. The replacement, NSXPCConnection, seems to require +// an assistant process that lives inside the .app bundle. This would be more modern, but adds +// complexity and I think makes it impossible to just run the `obs` binary from the commandline. +// So let's stick with NSMachBootstrapServer at least until it fully goes away. +// At that point we can decide between NSXPCConnection and using the CoreFoundation versions of +// these APIs (which are, interestingly, not deprecated) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + self.port = [[NSMachBootstrapServer sharedInstance] + servicePortWithName:@MACH_SERVICE_NAME]; +#pragma clang diagnostic pop + if (self.port == nil) { + // This probably means another instance is running. + blog(LOG_ERROR, "Unable to open mach server port."); + return; + } + + self.port.delegate = self; + + self.runLoop = [NSRunLoop currentRunLoop]; + [self.runLoop addPort:self.port forMode:NSDefaultRunLoopMode]; + + blog(LOG_DEBUG, "mach server running!"); +} + +- (void)handlePortMessage:(NSPortMessage *)message +{ + switch (message.msgid) { + case MachMsgIdConnect: + if (message.sendPort != nil) { + blog(LOG_DEBUG, + "mach server received connect message from port %d!", + ((NSMachPort *)message.sendPort).machPort); + [self.clientPorts addObject:message.sendPort]; + } + break; + default: + blog(LOG_ERROR, "Unexpected mach message ID %u", + (unsigned)message.msgid); + break; + } +} + +- (void)sendMessageToClientsWithMsgId:(uint32_t)msgId + components:(nullable NSArray *)components +{ + if ([self.clientPorts count] <= 0) { + return; + } + + NSMutableSet *removedPorts = [NSMutableSet set]; + + for (NSPort *port in self.clientPorts) { + @try { + NSPortMessage *message = [[NSPortMessage alloc] + initWithSendPort:port + receivePort:nil + components:components]; + message.msgid = msgId; + if (![message + sendBeforeDate: + [NSDate dateWithTimeIntervalSinceNow: + 1.0]]) { + blog(LOG_DEBUG, + "failed to send message to %d, removing it from the clients!", + ((NSMachPort *)port).machPort); + [removedPorts addObject:port]; + } + } @catch (NSException *exception) { + blog(LOG_DEBUG, + "failed to send message (exception) to %d, removing it from the clients!", + ((NSMachPort *)port).machPort); + [removedPorts addObject:port]; + } + } + + // Remove dead ports if necessary + [self.clientPorts minusSet:removedPorts]; +} + +- (void)sendFrameWithSize:(NSSize)size + timestamp:(uint64_t)timestamp + fpsNumerator:(uint32_t)fpsNumerator + fpsDenominator:(uint32_t)fpsDenominator + frameBytes:(uint8_t *)frameBytes +{ + if ([self.clientPorts count] <= 0) { + return; + } + + @autoreleasepool { + CGFloat width = size.width; + NSData *widthData = [NSData dataWithBytes:&width + length:sizeof(width)]; + CGFloat height = size.height; + NSData *heightData = [NSData dataWithBytes:&height + length:sizeof(height)]; + NSData *timestampData = [NSData + dataWithBytes:×tamp + length:sizeof(timestamp)]; + NSData *fpsNumeratorData = [NSData + dataWithBytes:&fpsNumerator + length:sizeof(fpsNumerator)]; + NSData *fpsDenominatorData = [NSData + dataWithBytes:&fpsDenominator + length:sizeof(fpsDenominator)]; + + // NOTE: I'm not totally sure about the safety of dataWithBytesNoCopy in this context. + // Seems like there could potentially be an issue if the frameBuffer went away before the + // mach message finished sending. But it seems to be working and avoids a memory copy. Alternately + // we could do something like + // NSData *frameData = [NSData dataWithBytes:(void *)frameBytes length:size.width * size.height * 2]; + NSData *frameData = [NSData + dataWithBytesNoCopy:(void *)frameBytes + length:size.width * size.height * 2 + freeWhenDone:NO]; + [self sendMessageToClientsWithMsgId:MachMsgIdFrame + components:@[ + widthData, heightData, + timestampData, frameData, + fpsNumeratorData, + fpsDenominatorData + ]]; + } +} + +- (void)stop +{ + blog(LOG_DEBUG, "sending stop message to %lu clients", + self.clientPorts.count); + [self sendMessageToClientsWithMsgId:MachMsgIdStop components:nil]; +} + +@end diff --git a/plugins/mac-virtualcam/src/obs-plugin/data/locale/ar-SA.ini b/plugins/mac-virtualcam/src/obs-plugin/data/locale/ar-SA.ini new file mode 100644 index 0000000..7f38f86 --- /dev/null +++ b/plugins/mac-virtualcam/src/obs-plugin/data/locale/ar-SA.ini @@ -0,0 +1,2 @@ +Plugin_Name="كاميرا ويب افتراضية macOS" + diff --git a/plugins/mac-virtualcam/src/obs-plugin/data/locale/az-AZ.ini b/plugins/mac-virtualcam/src/obs-plugin/data/locale/az-AZ.ini new file mode 100644 index 0000000..5c5bc69 --- /dev/null +++ b/plugins/mac-virtualcam/src/obs-plugin/data/locale/az-AZ.ini @@ -0,0 +1,2 @@ +Plugin_Name="macOS Əyani Veb Kamera" + diff --git a/plugins/mac-virtualcam/src/obs-plugin/data/locale/ca-ES.ini b/plugins/mac-virtualcam/src/obs-plugin/data/locale/ca-ES.ini new file mode 100644 index 0000000..450e28f --- /dev/null +++ b/plugins/mac-virtualcam/src/obs-plugin/data/locale/ca-ES.ini @@ -0,0 +1,2 @@ +Plugin_Name="Càmera web virtual del macOS" + diff --git a/plugins/mac-virtualcam/src/obs-plugin/data/locale/cs-CZ.ini b/plugins/mac-virtualcam/src/obs-plugin/data/locale/cs-CZ.ini new file mode 100644 index 0000000..3b492fd --- /dev/null +++ b/plugins/mac-virtualcam/src/obs-plugin/data/locale/cs-CZ.ini @@ -0,0 +1,2 @@ +Plugin_Name="macOS virtuální webkamera" + diff --git a/plugins/mac-virtualcam/src/obs-plugin/data/locale/da-DK.ini b/plugins/mac-virtualcam/src/obs-plugin/data/locale/da-DK.ini new file mode 100644 index 0000000..5795b45 --- /dev/null +++ b/plugins/mac-virtualcam/src/obs-plugin/data/locale/da-DK.ini @@ -0,0 +1,2 @@ +Plugin_Name="macOS Virtual Webcam" + diff --git a/plugins/mac-virtualcam/src/obs-plugin/data/locale/de-DE.ini b/plugins/mac-virtualcam/src/obs-plugin/data/locale/de-DE.ini new file mode 100644 index 0000000..381e60b --- /dev/null +++ b/plugins/mac-virtualcam/src/obs-plugin/data/locale/de-DE.ini @@ -0,0 +1,2 @@ +Plugin_Name="Virtuelle Kamera für macOS" + diff --git a/plugins/mac-virtualcam/src/obs-plugin/data/locale/en-GB.ini b/plugins/mac-virtualcam/src/obs-plugin/data/locale/en-GB.ini new file mode 100644 index 0000000..5795b45 --- /dev/null +++ b/plugins/mac-virtualcam/src/obs-plugin/data/locale/en-GB.ini @@ -0,0 +1,2 @@ +Plugin_Name="macOS Virtual Webcam" + diff --git a/plugins/mac-virtualcam/src/obs-plugin/data/locale/en-US.ini b/plugins/mac-virtualcam/src/obs-plugin/data/locale/en-US.ini new file mode 100644 index 0000000..d8042d4 --- /dev/null +++ b/plugins/mac-virtualcam/src/obs-plugin/data/locale/en-US.ini @@ -0,0 +1 @@ +Plugin_Name="macOS Virtual Webcam" diff --git a/plugins/mac-virtualcam/src/obs-plugin/data/locale/es-ES.ini b/plugins/mac-virtualcam/src/obs-plugin/data/locale/es-ES.ini new file mode 100644 index 0000000..8a1206e --- /dev/null +++ b/plugins/mac-virtualcam/src/obs-plugin/data/locale/es-ES.ini @@ -0,0 +1,2 @@ +Plugin_Name="Cámara Web Virtual macOS" + diff --git a/plugins/mac-virtualcam/src/obs-plugin/data/locale/et-EE.ini b/plugins/mac-virtualcam/src/obs-plugin/data/locale/et-EE.ini new file mode 100644 index 0000000..40b57dd --- /dev/null +++ b/plugins/mac-virtualcam/src/obs-plugin/data/locale/et-EE.ini @@ -0,0 +1,2 @@ +Plugin_Name="macOS virtuaalne veebikaamera" + diff --git a/plugins/mac-virtualcam/src/obs-plugin/data/locale/fa-IR.ini b/plugins/mac-virtualcam/src/obs-plugin/data/locale/fa-IR.ini new file mode 100644 index 0000000..e48b63c --- /dev/null +++ b/plugins/mac-virtualcam/src/obs-plugin/data/locale/fa-IR.ini @@ -0,0 +1,2 @@ +Plugin_Name="وبکم مجازی سیستم عامل مک" + diff --git a/plugins/mac-virtualcam/src/obs-plugin/data/locale/fi-FI.ini b/plugins/mac-virtualcam/src/obs-plugin/data/locale/fi-FI.ini new file mode 100644 index 0000000..10cdc46 --- /dev/null +++ b/plugins/mac-virtualcam/src/obs-plugin/data/locale/fi-FI.ini @@ -0,0 +1,2 @@ +Plugin_Name="macOS virtuaalinen web-kamera" + diff --git a/plugins/mac-virtualcam/src/obs-plugin/data/locale/fr-FR.ini b/plugins/mac-virtualcam/src/obs-plugin/data/locale/fr-FR.ini new file mode 100644 index 0000000..2aa590c --- /dev/null +++ b/plugins/mac-virtualcam/src/obs-plugin/data/locale/fr-FR.ini @@ -0,0 +1,2 @@ +Plugin_Name="Webcam virtuelle macOS" + diff --git a/plugins/mac-virtualcam/src/obs-plugin/data/locale/gl-ES.ini b/plugins/mac-virtualcam/src/obs-plugin/data/locale/gl-ES.ini new file mode 100644 index 0000000..041c644 --- /dev/null +++ b/plugins/mac-virtualcam/src/obs-plugin/data/locale/gl-ES.ini @@ -0,0 +1,2 @@ +Plugin_Name="Cámara Web Virtual do macOS" + diff --git a/plugins/mac-virtualcam/src/obs-plugin/data/locale/he-IL.ini b/plugins/mac-virtualcam/src/obs-plugin/data/locale/he-IL.ini new file mode 100644 index 0000000..397b742 --- /dev/null +++ b/plugins/mac-virtualcam/src/obs-plugin/data/locale/he-IL.ini @@ -0,0 +1,2 @@ +Plugin_Name="מצלמת רשת וירטואלית macOS" + diff --git a/plugins/mac-virtualcam/src/obs-plugin/data/locale/hu-HU.ini b/plugins/mac-virtualcam/src/obs-plugin/data/locale/hu-HU.ini new file mode 100644 index 0000000..036c546 --- /dev/null +++ b/plugins/mac-virtualcam/src/obs-plugin/data/locale/hu-HU.ini @@ -0,0 +1,2 @@ +Plugin_Name="macOS Virtuális Webkamera" + diff --git a/plugins/mac-virtualcam/src/obs-plugin/data/locale/id-ID.ini b/plugins/mac-virtualcam/src/obs-plugin/data/locale/id-ID.ini new file mode 100644 index 0000000..d0079f6 --- /dev/null +++ b/plugins/mac-virtualcam/src/obs-plugin/data/locale/id-ID.ini @@ -0,0 +1,2 @@ +Plugin_Name="kamera web Virtual macOS" + diff --git a/plugins/mac-virtualcam/src/obs-plugin/data/locale/it-IT.ini b/plugins/mac-virtualcam/src/obs-plugin/data/locale/it-IT.ini new file mode 100644 index 0000000..fc59216 --- /dev/null +++ b/plugins/mac-virtualcam/src/obs-plugin/data/locale/it-IT.ini @@ -0,0 +1,2 @@ +Plugin_Name="Webcam Virtuale macOS" + diff --git a/plugins/mac-virtualcam/src/obs-plugin/data/locale/ja-JP.ini b/plugins/mac-virtualcam/src/obs-plugin/data/locale/ja-JP.ini new file mode 100644 index 0000000..ec0a862 --- /dev/null +++ b/plugins/mac-virtualcam/src/obs-plugin/data/locale/ja-JP.ini @@ -0,0 +1,2 @@ +Plugin_Name="macOS仮想ウェブカメラ" + diff --git a/plugins/mac-virtualcam/src/obs-plugin/data/locale/ka-GE.ini b/plugins/mac-virtualcam/src/obs-plugin/data/locale/ka-GE.ini new file mode 100644 index 0000000..cd38d8c --- /dev/null +++ b/plugins/mac-virtualcam/src/obs-plugin/data/locale/ka-GE.ini @@ -0,0 +1,2 @@ +Plugin_Name="macOS ვირტუალური კამერა" + diff --git a/plugins/mac-virtualcam/src/obs-plugin/data/locale/kab-KAB.ini b/plugins/mac-virtualcam/src/obs-plugin/data/locale/kab-KAB.ini new file mode 100644 index 0000000..b7cb4a9 --- /dev/null +++ b/plugins/mac-virtualcam/src/obs-plugin/data/locale/kab-KAB.ini @@ -0,0 +1,2 @@ +Plugin_Name="takamiṛat tuhlist macOS" + diff --git a/plugins/mac-virtualcam/src/obs-plugin/data/locale/ko-KR.ini b/plugins/mac-virtualcam/src/obs-plugin/data/locale/ko-KR.ini new file mode 100644 index 0000000..86d27a2 --- /dev/null +++ b/plugins/mac-virtualcam/src/obs-plugin/data/locale/ko-KR.ini @@ -0,0 +1,2 @@ +Plugin_Name="macOS 가상 웹캠" + diff --git a/plugins/mac-virtualcam/src/obs-plugin/data/locale/nl-NL.ini b/plugins/mac-virtualcam/src/obs-plugin/data/locale/nl-NL.ini new file mode 100644 index 0000000..5795b45 --- /dev/null +++ b/plugins/mac-virtualcam/src/obs-plugin/data/locale/nl-NL.ini @@ -0,0 +1,2 @@ +Plugin_Name="macOS Virtual Webcam" + diff --git a/plugins/mac-virtualcam/src/obs-plugin/data/locale/pl-PL.ini b/plugins/mac-virtualcam/src/obs-plugin/data/locale/pl-PL.ini new file mode 100644 index 0000000..f612dd5 --- /dev/null +++ b/plugins/mac-virtualcam/src/obs-plugin/data/locale/pl-PL.ini @@ -0,0 +1,2 @@ +Plugin_Name="Wirtualna kamera macOS" + diff --git a/plugins/mac-virtualcam/src/obs-plugin/data/locale/pt-BR.ini b/plugins/mac-virtualcam/src/obs-plugin/data/locale/pt-BR.ini new file mode 100644 index 0000000..ca556b3 --- /dev/null +++ b/plugins/mac-virtualcam/src/obs-plugin/data/locale/pt-BR.ini @@ -0,0 +1,2 @@ +Plugin_Name="Webcam Virtual do macOS" + diff --git a/plugins/mac-virtualcam/src/obs-plugin/data/locale/pt-PT.ini b/plugins/mac-virtualcam/src/obs-plugin/data/locale/pt-PT.ini new file mode 100644 index 0000000..17e5537 --- /dev/null +++ b/plugins/mac-virtualcam/src/obs-plugin/data/locale/pt-PT.ini @@ -0,0 +1,2 @@ +Plugin_Name="Webcam Virtual do MacOS" + diff --git a/plugins/mac-virtualcam/src/obs-plugin/data/locale/ru-RU.ini b/plugins/mac-virtualcam/src/obs-plugin/data/locale/ru-RU.ini new file mode 100644 index 0000000..cda2b81 --- /dev/null +++ b/plugins/mac-virtualcam/src/obs-plugin/data/locale/ru-RU.ini @@ -0,0 +1,2 @@ +Plugin_Name="macOS виртуальная веб-камера" + diff --git a/plugins/mac-virtualcam/src/obs-plugin/data/locale/sk-SK.ini b/plugins/mac-virtualcam/src/obs-plugin/data/locale/sk-SK.ini new file mode 100644 index 0000000..c451f9e --- /dev/null +++ b/plugins/mac-virtualcam/src/obs-plugin/data/locale/sk-SK.ini @@ -0,0 +1,2 @@ +Plugin_Name="macOS Virtuálna Webkamera" + diff --git a/plugins/mac-virtualcam/src/obs-plugin/data/locale/sl-SI.ini b/plugins/mac-virtualcam/src/obs-plugin/data/locale/sl-SI.ini new file mode 100644 index 0000000..eed040a --- /dev/null +++ b/plugins/mac-virtualcam/src/obs-plugin/data/locale/sl-SI.ini @@ -0,0 +1,2 @@ +Plugin_Name="macOS virtualna spletna kamera" + diff --git a/plugins/mac-virtualcam/src/obs-plugin/data/locale/sv-SE.ini b/plugins/mac-virtualcam/src/obs-plugin/data/locale/sv-SE.ini new file mode 100644 index 0000000..7ce249e --- /dev/null +++ b/plugins/mac-virtualcam/src/obs-plugin/data/locale/sv-SE.ini @@ -0,0 +1,2 @@ +Plugin_Name="macOS virtuell webbkamera" + diff --git a/plugins/mac-virtualcam/src/obs-plugin/data/locale/tr-TR.ini b/plugins/mac-virtualcam/src/obs-plugin/data/locale/tr-TR.ini new file mode 100644 index 0000000..ddc08fe --- /dev/null +++ b/plugins/mac-virtualcam/src/obs-plugin/data/locale/tr-TR.ini @@ -0,0 +1,2 @@ +Plugin_Name="macOS Sanal Web Kamerası" + diff --git a/plugins/mac-virtualcam/src/obs-plugin/data/locale/uk-UA.ini b/plugins/mac-virtualcam/src/obs-plugin/data/locale/uk-UA.ini new file mode 100644 index 0000000..0d936bc --- /dev/null +++ b/plugins/mac-virtualcam/src/obs-plugin/data/locale/uk-UA.ini @@ -0,0 +1,2 @@ +Plugin_Name="Віртуальна вебкамера macOS" + diff --git a/plugins/mac-virtualcam/src/obs-plugin/data/locale/zh-CN.ini b/plugins/mac-virtualcam/src/obs-plugin/data/locale/zh-CN.ini new file mode 100644 index 0000000..44b646e --- /dev/null +++ b/plugins/mac-virtualcam/src/obs-plugin/data/locale/zh-CN.ini @@ -0,0 +1,2 @@ +Plugin_Name="macOS 虚拟摄像头" + diff --git a/plugins/mac-virtualcam/src/obs-plugin/data/locale/zh-TW.ini b/plugins/mac-virtualcam/src/obs-plugin/data/locale/zh-TW.ini new file mode 100644 index 0000000..6b808c1 --- /dev/null +++ b/plugins/mac-virtualcam/src/obs-plugin/data/locale/zh-TW.ini @@ -0,0 +1,2 @@ +Plugin_Name="macOS 虛擬攝像機" + diff --git a/plugins/mac-virtualcam/src/obs-plugin/plugin-main.mm b/plugins/mac-virtualcam/src/obs-plugin/plugin-main.mm new file mode 100644 index 0000000..37437f4 --- /dev/null +++ b/plugins/mac-virtualcam/src/obs-plugin/plugin-main.mm @@ -0,0 +1,208 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "OBSDALMachServer.h" +#include "Defines.h" + +OBS_DECLARE_MODULE() +OBS_MODULE_USE_DEFAULT_LOCALE("mac-virtualcam", "en-US") +MODULE_EXPORT const char *obs_module_description(void) +{ + return "macOS virtual webcam output"; +} + +obs_output_t *outputRef; +obs_video_info videoInfo; +static OBSDALMachServer *sMachServer; + +static bool check_dal_plugin() +{ + NSFileManager *fileManager = [NSFileManager defaultManager]; + + NSString *dalPluginDestinationPath = + @"/Library/CoreMediaIO/Plug-Ins/DAL/"; + NSString *dalPluginFileName = [dalPluginDestinationPath + stringByAppendingString:@"obs-mac-virtualcam.plugin"]; + + BOOL dalPluginInstalled = + [fileManager fileExistsAtPath:dalPluginFileName]; + BOOL dalPluginUpdateNeeded = NO; + + if (dalPluginInstalled) { + NSString *dalPluginPlistPath = [dalPluginFileName + stringByAppendingString:@"/Contents/Info.plist"]; + NSDictionary *dalPluginInfoPlist = [NSDictionary + dictionaryWithContentsOfURL: + [NSURL fileURLWithPath:dalPluginPlistPath] + error:nil]; + NSString *dalPluginVersion = [dalPluginInfoPlist + valueForKey:@"CFBundleShortVersionString"]; + const char *obsVersion = obs_get_version_string(); + + if (![dalPluginVersion isEqualToString:@(obsVersion)]) { + dalPluginUpdateNeeded = YES; + } + } else { + dalPluginUpdateNeeded = YES; + } + + if (dalPluginUpdateNeeded) { + NSString *dalPluginSourcePath; + NSRunningApplication *app = + [NSRunningApplication currentApplication]; + + if ([app bundleIdentifier] != nil) { + NSURL *bundleURL = [app bundleURL]; + NSString *pluginPath = + @"Contents/Resources/data/obs-mac-virtualcam.plugin"; + + NSURL *pluginUrl = [bundleURL + URLByAppendingPathComponent:pluginPath]; + dalPluginSourcePath = [pluginUrl path]; + } else { + dalPluginSourcePath = [[[[app executableURL] + URLByAppendingPathComponent: + @"../data/obs-mac-virtualcam.plugin"] + path] + stringByReplacingOccurrencesOfString:@"obs/" + withString:@""]; + } + + if ([fileManager fileExistsAtPath:dalPluginSourcePath]) { + NSString *copyCmd = [NSString + stringWithFormat: + @"do shell script \"cp -R '%@' '%@'\" with administrator privileges", + dalPluginSourcePath, + dalPluginDestinationPath]; + + NSDictionary *errorDict; + NSAppleEventDescriptor *returnDescriptor = NULL; + NSAppleScript *scriptObject = + [[NSAppleScript alloc] initWithSource:copyCmd]; + returnDescriptor = + [scriptObject executeAndReturnError:&errorDict]; + if (errorDict != nil) { + const char *errorMessage = [[errorDict + objectForKey:@"NSAppleScriptErrorMessage"] + UTF8String]; + blog(LOG_INFO, + "[macOS] VirtualCam DAL Plugin Installation status: %s", + errorMessage); + return false; + } + } else { + blog(LOG_INFO, + "[macOS] VirtualCam DAL Plugin not shipped with OBS"); + return false; + } + } + return true; +} + +static const char *virtualcam_output_get_name(void *type_data) +{ + (void)type_data; + return obs_module_text("Plugin_Name"); +} + +// This is a dummy pointer so we have something to return from virtualcam_output_create +static void *data = &data; + +static void *virtualcam_output_create(obs_data_t *settings, + obs_output_t *output) +{ + outputRef = output; + + blog(LOG_DEBUG, "output_create"); + sMachServer = [[OBSDALMachServer alloc] init]; + return data; +} + +static void virtualcam_output_destroy(void *data) +{ + blog(LOG_DEBUG, "output_destroy"); + sMachServer = nil; +} + +static bool virtualcam_output_start(void *data) +{ + bool hasDalPlugin = check_dal_plugin(); + + if (!hasDalPlugin) { + return false; + } + + blog(LOG_DEBUG, "output_start"); + + [sMachServer run]; + + obs_get_video_info(&videoInfo); + + struct video_scale_info conversion = {}; + conversion.format = VIDEO_FORMAT_UYVY; + conversion.width = videoInfo.output_width; + conversion.height = videoInfo.output_height; + obs_output_set_video_conversion(outputRef, &conversion); + if (!obs_output_begin_data_capture(outputRef, 0)) { + return false; + } + + return true; +} + +static void virtualcam_output_stop(void *data, uint64_t ts) +{ + blog(LOG_DEBUG, "output_stop"); + obs_output_end_data_capture(outputRef); + [sMachServer stop]; +} + +static void virtualcam_output_raw_video(void *data, struct video_data *frame) +{ + uint8_t *outData = frame->data[0]; + if (frame->linesize[0] != (videoInfo.output_width * 2)) { + blog(LOG_ERROR, + "unexpected frame->linesize (expected:%d actual:%d)", + (videoInfo.output_width * 2), frame->linesize[0]); + } + + CGFloat width = videoInfo.output_width; + CGFloat height = videoInfo.output_height; + + [sMachServer sendFrameWithSize:NSMakeSize(width, height) + timestamp:frame->timestamp + fpsNumerator:videoInfo.fps_num + fpsDenominator:videoInfo.fps_den + frameBytes:outData]; +} + +struct obs_output_info virtualcam_output_info = { + .id = "virtualcam_output", + .flags = OBS_OUTPUT_VIDEO, + .get_name = virtualcam_output_get_name, + .create = virtualcam_output_create, + .destroy = virtualcam_output_destroy, + .start = virtualcam_output_start, + .stop = virtualcam_output_stop, + .raw_video = virtualcam_output_raw_video, +}; + +bool obs_module_load(void) +{ + blog(LOG_INFO, "version=%s", PLUGIN_VERSION); + + obs_register_output(&virtualcam_output_info); + + obs_data_t *obs_settings = obs_data_create(); + obs_data_set_bool(obs_settings, "vcamEnabled", true); + obs_apply_private_data(obs_settings); + obs_data_release(obs_settings); + + return true; +} diff --git a/plugins/mac-vth264/data/locale/az-AZ.ini b/plugins/mac-vth264/data/locale/az-AZ.ini index cda518a..7f94e77 100644 --- a/plugins/mac-vth264/data/locale/az-AZ.ini +++ b/plugins/mac-vth264/data/locale/az-AZ.ini @@ -1,3 +1,14 @@ +VTH264EncHW="Apple VT H264 Avadanlıq Təminatı Kodlayıcı" +VTH264EncSW="Apple VT H264 Proqram Təminatı Kodlayıcı" +VTEncoder="VideoToolbox Kodlayıcı" +Bitrate="Bit sürəti" +UseMaxBitrate="Bit sürətini limitlə" +MaxBitrate="Maksimal bit sürəti" +MaxBitrateWindow="Maksimal bit sürəti pəncərəsi (saniyə)" +KeyframeIntervalSec="Açar Kadr Aralığı (saniyə, 0=avtomatik)" +Profile="Profil" None="(Heç biri)" +DefaultEncoder="(İlkin Kodlayıcı)" +UseBFrames="B Kadrlarını istifadə et" diff --git a/plugins/mac-vth264/data/locale/de-DE.ini b/plugins/mac-vth264/data/locale/de-DE.ini index 17fb38d..51013b5 100644 --- a/plugins/mac-vth264/data/locale/de-DE.ini +++ b/plugins/mac-vth264/data/locale/de-DE.ini @@ -1,6 +1,6 @@ -VTH264EncHW="Apple‐VT‐H264‐Hardwareencoder" -VTH264EncSW="Apple‐VT‐H264‐Softwareencoder" -VTEncoder="VideoToolbox‐Encoder" +VTH264EncHW="Apple-VT-H264-Hardwareencoder" +VTH264EncSW="Apple-VT-H264-Softwareencoder" +VTEncoder="VideoToolbox-Encoder" Bitrate="Bitrate" UseMaxBitrate="Limitiere Bitrate" MaxBitrate="Maximale Bitrate" @@ -9,6 +9,6 @@ KeyframeIntervalSec="Keyframeintervall in Sek. (0 = automatisch)" Profile="Profil" None="(Nichts)" DefaultEncoder="(Standardencoder)" -UseBFrames="B‐Frames verwenden" +UseBFrames="B-Frames verwenden" diff --git a/plugins/mac-vth264/data/locale/id-ID.ini b/plugins/mac-vth264/data/locale/id-ID.ini index 1bd8c1d..ca51f8d 100644 --- a/plugins/mac-vth264/data/locale/id-ID.ini +++ b/plugins/mac-vth264/data/locale/id-ID.ini @@ -1,4 +1,4 @@ -VTH264EncHW="Enkoder Hardware Apple VT H264" +VTH264EncHW="Enkoder Perangkat Keras Apple VT H264" VTH264EncSW="Enkoder Software Apple VT H264" VTEncoder="Enkoder VideoToolbox" Bitrate="Bitrate" diff --git a/plugins/mac-vth264/data/locale/kab-KAB.ini b/plugins/mac-vth264/data/locale/kab-KAB.ini new file mode 100644 index 0000000..5f0a6fe --- /dev/null +++ b/plugins/mac-vth264/data/locale/kab-KAB.ini @@ -0,0 +1,14 @@ +VTH264EncHW="Asettengal n warrum Apple VT H264" +VTH264EncSW="Asettengal n useɣẓan Apple VT H264" +VTEncoder="Asettengal n uvidyu Toolbox" +Bitrate="Aktum" +UseMaxBitrate="Eg tilist i uktum" +MaxBitrate="Aktum afellay" +MaxBitrateWindow="Asfaylu n uktum afellay (tasinin)" +KeyframeIntervalSec="Azilal n yikataren yufraren (tasinin, 0=awurman)" +Profile="Amaɣnu" +None="(Ulac)" +DefaultEncoder="(Asettengal n lexṣas)" +UseBFrames="Seqdec B-Frames" + + diff --git a/plugins/mac-vth264/data/locale/ro-RO.ini b/plugins/mac-vth264/data/locale/ro-RO.ini index 0a9e2a8..9cd19d6 100644 --- a/plugins/mac-vth264/data/locale/ro-RO.ini +++ b/plugins/mac-vth264/data/locale/ro-RO.ini @@ -9,6 +9,6 @@ KeyframeIntervalSec="Interval de cadre cheie (secunde, 0=auto)" Profile="Profil" None="(Niciunul)" DefaultEncoder="(Codificator implicit)" -UseBFrames="Folosește B-frames" +UseBFrames="Folosește cadre B" diff --git a/plugins/mac-vth264/data/locale/vi-VN.ini b/plugins/mac-vth264/data/locale/vi-VN.ini index 2b73d96..fc41cde 100644 --- a/plugins/mac-vth264/data/locale/vi-VN.ini +++ b/plugins/mac-vth264/data/locale/vi-VN.ini @@ -4,6 +4,7 @@ VTEncoder="Bộ mã hóa VideoToolbox" Bitrate="Bitrate" UseMaxBitrate="Giới hạn bitrate" MaxBitrate="Bitrate tối đa" +MaxBitrateWindow="Tốc độ bit tối đa của cửa sổ (giây)" KeyframeIntervalSec="Thời gian đặt Keyframe (giây, 0=tự động)" Profile="Hồ sơ" None="(Không)" diff --git a/plugins/obs-ffmpeg/CMakeLists.txt b/plugins/obs-ffmpeg/CMakeLists.txt index 2ad43d6..9df656b 100644 --- a/plugins/obs-ffmpeg/CMakeLists.txt +++ b/plugins/obs-ffmpeg/CMakeLists.txt @@ -20,8 +20,9 @@ set(obs-ffmpeg_config_HEADERS "${CMAKE_CURRENT_BINARY_DIR}/obs-ffmpeg-config.h") set(obs-ffmpeg_HEADERS + obs-ffmpeg-compat.h obs-ffmpeg-formats.h - obs-ffmpeg-compat.h) + obs-ffmpeg-mux.h) set(obs-ffmpeg_SOURCES obs-ffmpeg.c @@ -29,6 +30,7 @@ set(obs-ffmpeg_SOURCES obs-ffmpeg-nvenc.c obs-ffmpeg-output.c obs-ffmpeg-mux.c + obs-ffmpeg-hls-mux.c obs-ffmpeg-source.c) if(UNIX AND NOT APPLE) diff --git a/plugins/obs-ffmpeg/data/locale/de-DE.ini b/plugins/obs-ffmpeg/data/locale/de-DE.ini index d990c98..4dbe978 100644 --- a/plugins/obs-ffmpeg/data/locale/de-DE.ini +++ b/plugins/obs-ffmpeg/data/locale/de-DE.ini @@ -1,6 +1,6 @@ -FFmpegOutput="FFmpeg‐Ausgabe" -FFmpegAAC="FFmpeg‐Standard‐AAC‐Encoder" -FFmpegOpus="FFmpeg‐Opus‐Encoder" +FFmpegOutput="FFmpeg-Ausgabe" +FFmpegAAC="FFmpeg-Standard-AAC-Encoder" +FFmpegOpus="FFmpeg-Opus-Encoder" Bitrate="Bitrate" MaxBitrate="Max. Bitrate" Preset="Voreinstellung" @@ -9,9 +9,9 @@ RateControl="Qualitätsregulierungsmethode" KeyframeIntervalSec="Keyframeintervall in Sek. (0 = automatisch)" Lossless="Verlustfrei" -BFrames="Max. B‐Frames" +BFrames="Max. B-Frames" -NVENC.Use2Pass="Two‐Pass‐Codierung verwenden" +NVENC.Use2Pass="Two-Pass-Codierung verwenden" NVENC.Preset.default="Leistung" NVENC.Preset.hq="Qualität" NVENC.Preset.hp="Max. Leistung" @@ -20,10 +20,10 @@ NVENC.Preset.ll="Niedrige Latenz" NVENC.Preset.llhq="Niedrige Latenz und Qualität" NVENC.Preset.llhp="Niedrige Latenz und Leistung" NVENC.LookAhead="Lookahead" -NVENC.LookAhead.ToolTip="Aktiviert dynamische B‐Frames.\n\nWenn deaktiviert, wird der Encoder immer die Anzahl der B‐Frames verwenden, die in der Einstellung „Max. B‐Frames“ angegeben sind.\n\nWenn aktiviert, wird die visuelle Qualität erhöht, indem nur so viele B‐Frames bis zum Maximum verwendet werden, wie benötigt.\n(Resultiert in eine höhere GPU‐Nutzung.)" +NVENC.LookAhead.ToolTip="Aktiviert dynamische B-Frames.\n\nWenn deaktiviert, wird der Encoder immer die Anzahl der B-Frames verwenden, die in der Einstellung „Max. B-Frames“ angegeben sind.\n\nWenn aktiviert, wird die visuelle Qualität erhöht, indem nur so viele B-Frames bis zum Maximum verwendet werden, wie benötigt.\n(Resultiert in eine höhere GPU-Nutzung.)" NVENC.PsychoVisualTuning="Psycho Visual Tuning" -NVENC.PsychoVisualTuning.ToolTip="Aktiviert Encodereinstellungen, die die Verwendung der Bitrate für eine erhöhte wahrgenommene visuelle Qualität optimieren,\ninsbesondere in Situationen mit hoher Bewegung.\n(Resultiert in eine höhere GPU‐Nutzung.)" -NVENC.CQLevel="CQ‐Level" +NVENC.PsychoVisualTuning.ToolTip="Aktiviert Encodereinstellungen, die die Verwendung der Bitrate für eine erhöhte wahrgenommene visuelle Qualität optimieren,\ninsbesondere in Situationen mit hoher Bewegung.\n(Resultiert in eine höhere GPU-Nutzung.)" +NVENC.CQLevel="CQ-Level" FFmpegSource="Medienquelle" LocalFile="Lokale Datei" @@ -37,7 +37,7 @@ Advanced="Erweitert" RestartWhenActivated="Wiedergabe bei Quellenaktivierung erneut starten" CloseFileWhenInactive="Datei schließen, wenn inaktiv" CloseFileWhenInactive.ToolTip="Schließt die Datei, wenn die Quelle im Stream oder in der Aufnahme nicht angezeigt wird.\nDies ermöglicht Änderungen an der Datei vorzunehmen,\nwas aber zu Reaktivierungsverzögerungen führen kann." -ColorRange="YUV‐Farbbereich" +ColorRange="YUV-Farbbereich" ColorRange.Auto="Automatisch" ColorRange.Partial="Teilweise" ColorRange.Full="Voll" @@ -56,16 +56,16 @@ MediaFileFilter.AllFiles="Alle Dateien" ReplayBuffer="Wiederholungspuffer" ReplayBuffer.Save="Wiederholung speichern" -HelperProcessFailed="Der Aufnahme‐Helfer‐Prozess kann nicht gestartet werden. Überprüfen Sie, ob OBS‐Dateien nicht von einer Drittanbieter‐Antiviren‐/Sicherheitssoftware blockiert oder entfernt werden." +HelperProcessFailed="Der Aufnahme-Helfer-Prozess kann nicht gestartet werden. Überprüfen Sie, ob OBS-Dateien nicht von einer Drittanbieter-Antiviren-/Sicherheitssoftware blockiert oder entfernt werden." UnableToWritePath="Kann nicht zu %1 schreiben. Vergewissern Sie sich, dass Sie einen Aufnahmepfad verwenden, für den Ihr Benutzerkonto Schreibrechte hat und dass genügend Speicherplatz zur Verfügung steht." -WarnWindowsDefender="Wenn Windows‐10‐Ransomware‐Schutz aktiviert ist, kann dies auch den Fehler auslösen. Versuchen Sie, den überwachten Ordnerzugriff in „Windows‐Sicherheit“ → „Viren‐ & Bedrohungsschutz“ auszuschalten." +WarnWindowsDefender="Wenn Windows-10-Ransomware-Schutz aktiviert ist, kann dies auch den Fehler verursachen. Versuchen Sie, den überwachten Ordnerzugriff in Windows-Sicherheit → Viren- & Bedrohungsschutz auszuschalten." -NVENC.Error="Fehler beim Öffnen des NVENC‐Codecs: %1" +NVENC.Error="Fehler beim Öffnen des NVENC-Codecs: %1" NVENC.GenericError="Überprüfen Sie, ob Ihre Grafiktreiber aktuell sind. Versuchen Sie, andere Aufnahmesoftware wie NVIDIA Shadowplay oder Windows 10 Game DVR zu schließen, welche NVENC möglicherweise verwendet." NVENC.BadGPUIndex="Sie haben die GPU %1 in Ihren Ausgabeencodereinstellungen ausgewählt. Setzen Sie diesen Wert wieder auf 0 und versuchen Sie es erneut." -NVENC.OutdatedDriver="Ihr aktueller Grafikkartentreiber unterstützt diese NVENC‐Version nicht. Bitte aktualisieren Sie Ihre Treiber." -NVENC.UnsupportedDevice="NVENC‐Fehler: Nicht unterstütztes Gerät. Überprüfen Sie, ob Ihre Grafikkarte NVENC unterstützt und Ihre Treiber aktuell sind." -NVENC.TooManySessions="NVENC‐Fehler: Zu viele gleichzeitige Sitzungen. Versuchen Sie, andere Aufnahmesoftware wie NVIDIA Shadowplay oder Windows 10 Game DVR zu schließen, welche NVENC möglicherweise verwendet." +NVENC.OutdatedDriver="Ihr aktueller Grafikkartentreiber unterstützt diese NVENC-Version nicht. Bitte aktualisieren Sie Ihre Treiber." +NVENC.UnsupportedDevice="NVENC-Fehler: Nicht unterstütztes Gerät. Überprüfen Sie, ob Ihre Grafikkarte NVENC unterstützt und Ihre Treiber aktuell sind." +NVENC.TooManySessions="NVENC-Fehler: Zu viele gleichzeitige Sitzungen. Versuchen Sie, andere Aufnahmesoftware wie NVIDIA Shadowplay oder Windows 10 Game DVR zu schließen, welche NVENC möglicherweise verwendet." NVENC.CheckDrivers="Bitte überprüfen Sie, ob Ihre Grafiktreiber aktuell sind." ReconnectDelayTime="Wiederverbindungsverzögerung" diff --git a/plugins/obs-ffmpeg/data/locale/el-GR.ini b/plugins/obs-ffmpeg/data/locale/el-GR.ini index dfff5fc..d70c247 100644 --- a/plugins/obs-ffmpeg/data/locale/el-GR.ini +++ b/plugins/obs-ffmpeg/data/locale/el-GR.ini @@ -2,14 +2,22 @@ FFmpegOutput="Έξοδος FFmpeg" FFmpegAAC="FFmpeg προεπιλεγμένος κωδικοποιητής AAC" FFmpegOpus="FFmpeg Opus κωδικοποιητής" Bitrate="Ρυθμός μετάδοσης bit" +MaxBitrate="Μέγιστος ρυθμός μετάδοσης bit" Preset="Προκαθορισμένο στυλ" +Profile="Προφίλ" RateControl="Έλεγχος ρυθμού" KeyframeIntervalSec="Συχνότητα Καρέ-Κλειδιού (δευτερόλεπτα, 0=αυτόματο)" Lossless="Χωρίς απώλειες" NVENC.Use2Pass="Χρήση κωδικοποίησης δύο περασμάτων" +NVENC.Preset.default="Επιδόσεις" +NVENC.Preset.hq="Ποιότητα" +NVENC.Preset.hp="Μέγιστες Επιδόσεις" +NVENC.Preset.mq="Μέγιστη Ποιότητα" NVENC.Preset.ll="Χαμηλή Καθυστέρηση" +NVENC.Preset.llhq="Ποιότητα Χαμηλής Καθυστέρησης" +NVENC.Preset.llhp="Απόδοση Χαμηλής Καθυστέρησης" FFmpegSource="Πηγή Πολυμέσων" LocalFile="Τοπικό αρχείο" @@ -17,6 +25,7 @@ Looping="Επανάληψη" Input="Είσοδος" InputFormat="Μορφή Εισόδου" HardwareDecode="Χρήση αποκωδικοποίησης υλικού όταν είναι διαθέσιμη" +ClearOnMediaEnd="Μη δείχνεις τίποτα όταν τελειώνει η αναπαραγωγή" Advanced="Σύνθετες επιλογές" RestartWhenActivated="Επανεκκίνηση της αναπαραγωγής όταν η πηγή γίνεται ξανά ενεργή" CloseFileWhenInactive="Κλείσιμο του αρχείου όταν η πηγή είναι ανενεργή" @@ -25,7 +34,12 @@ ColorRange="Χώρος Χρωμάτων YUV" ColorRange.Auto="Αυτόματο" ColorRange.Partial="Μερικός" ColorRange.Full="Πλήρης" +RestartMedia="Επανέναρξη" +SpeedPercentage="Ταχύτητα" Seekable="Παρεχόμενη" +Play="Αναπαραγωγή" +Pause="Παύση" +Stop="Διακοπή" MediaFileFilter.AllMediaFiles="Όλα τα αρχεία πολυμέσων" MediaFileFilter.VideoFiles="Αρχεία Βίντεο" @@ -38,5 +52,11 @@ ReplayBuffer.Save="Αποθήκευση Replay" HelperProcessFailed="Αδυναμία έναρξης τού βοηθού της διαδικασίας εγγραφής. Ελέγξτε ότι τα αρχεία OBS δεν έχουν αποκλειστεί η καταργηθεί από ένα τρίτο antivirus / λογισμικό ασφαλείας." UnableToWritePath="Αδυναμία εγγραφής %1. Βεβαιωθείτε ότι χρησιμοποιείτε μια διαδρομή εγγραφής που επιτρέπεται για εγγραφή τού λογαριασμού χρήστη και ότι υπάρχει επαρκής χώρος στον σκληρό δίσκο." +NVENC.GenericError="Βεβαιωθείτε ότι οι οδηγοί βίντεο είναι ενημερωμένοι. Δοκιμάστε να κλείσετε άλλα λογισμικά βιντεοσκόπησης που μπορεί να χρησιμοποιούν το λογισμικό NVENC όπως το NVIDIA Shadowplay ή το Windows 10 Game DVR." +NVENC.BadGPUIndex="'Έχετε επιλέξει τη συσκευή GPU %1 στις ρυθμίσεις του αποκωδικοποιητή εξόδου. Αλλάξτε τη ρύθμιση στο 0 και ξαναδοκιμάστε." +NVENC.OutdatedDriver="Ο τρέχων οδηγός της κάρτας βίντεο δεν υποστηρίζει αυτή την έκδοση του λογισμικού NVENC, παρακαλώ ενημερώστε τους οδηγούς σας." +NVENC.UnsupportedDevice="Σφάλμα NVENC: Μη υποστηριζόμενη συσκευή. Ελέγξτε εάν η κάρτα γραφικών σας υποστηρίζει το λογισμικό NVENC και ότι οι οδηγοί της συσκευής είναι ενημερωμένοι." +NVENC.TooManySessions="Σφάλμα NVENC: Πάρα πολλές ταυτόχρονες χρήσεις. Δοκιμάστε να κλείσετε άλλα λογισμικά βιντεοσκόπησης που μπορεί να χρησιμοποιούν το λογισμικό NVENC όπως το NVIDIA Shadowplay ή το Windows 10 Game DVR." +NVENC.CheckDrivers="Παρακαλώ βεβαιωθείτε ότι οι οδηγοί βίντεο είναι ενημερωμένοι." diff --git a/plugins/obs-ffmpeg/data/locale/fa-IR.ini b/plugins/obs-ffmpeg/data/locale/fa-IR.ini index 830fde7..beaff9d 100644 --- a/plugins/obs-ffmpeg/data/locale/fa-IR.ini +++ b/plugins/obs-ffmpeg/data/locale/fa-IR.ini @@ -4,6 +4,7 @@ FFmpegOpus="اپوس FFmpeg تخمین" Bitrate="نرخ بیت" MaxBitrate="حداکثر میزان نرخ بیت" Preset="پیش فرض" +Profile="پروفایل" RateControl="کنترل نرخ" KeyframeIntervalSec="فاصله Keyframe (ثانیه 0 = خودکار)" Lossless="بدون تلف" @@ -19,15 +20,33 @@ NVENC.Preset.ll="زمان تاخیر کم" NVENC.Preset.llhq="کیفیت پایین و زمان تاخیر" NVENC.Preset.llhp="زمان تاخیر کم عملکرد" NVENC.LookAhead="پیش رو نگاه" +NVENC.LookAhead.ToolTip="فریم های B پویا را فعال می کند.\n\nاگر غیرفعال باشد، رمزگذار همیشه از تعداد فریم های B مشخص شده در تنظیمات \"حداکثر فریم B\" استفاده خواهد کرد.\n\nدر صورت فعال بودن، فقط با استفاده از تعداد زیادی کیفیت بصری فریم B حداکثر افزایش می یابد،\n مقدار استفاده از گرافیک افزایش می یابد." +NVENC.PsychoVisualTuning="تنظیم بصری روانی" +NVENC.PsychoVisualTuning.ToolTip="تنظیمات رمزگذار را که بهینه سازی استفاده از میزان بیت برای افزایش کیفیت بصری درک شده را امکان پذیر می کند، \nخصوصاً در شرایط با حرکت بالا، با استفاده بیشتر از گرافیک." +NVENC.CQLevel="سطح تدریج ثابت" +FFmpegSource="منبع رسانه" LocalFile="فایل محلی" Looping="چرخه" Input="ورودی" InputFormat="فرمت های ورودی" +BufferingMB="بافر شبکه" +HardwareDecode="در صورت وجود از رمزگشایی سخت افزاری استفاده کنید" +ClearOnMediaEnd="با پایان پخش، چیزی نشان داده نشود" +Advanced="پیشرفته" +RestartWhenActivated="با فعال شدن منبع پخش را دوباره شروع کنید" +CloseFileWhenInactive="بستن پرونده در صورت غیرفعال بودن" +CloseFileWhenInactive.ToolTip="وقتی منبع در جریان نمایش داده نمی شود یا\n ضبط نمی شود، پرونده را می بندد. این اجازه می دهد تا پرونده هنگام فعال نبودن منبع تغییر کند، \n اما ممکن است هنگام فعال شدن مجدد منبع، تأخیر در شروع وجود داشته باشد." +ColorRange="فضای رنگی YUV" ColorRange.Auto="خودکار" ColorRange.Partial="جزئی" ColorRange.Full="کامل" +RestartMedia="اجرا مجدد" +SpeedPercentage="سرعت" Seekable="جستجوگر" +Play="پخش" +Pause="مکث" +Stop="توقف" MediaFileFilter.AllMediaFiles="تمامی فایل های رسانه" MediaFileFilter.VideoFiles="فایل‌های ویدئویی" @@ -37,6 +56,17 @@ MediaFileFilter.AllFiles="همه‌ی فایل ها" ReplayBuffer="پخش مجدد بافر" ReplayBuffer.Save="ذخیره پخش مجدد" +HelperProcessFailed="فرآیند راهنمای ضبط شروع نمی شود. بررسی کنید که فایلهای OBS توسط هیچ یک از آنتی ویروس ها/نرم افزارهای امنیتی شخص ثالث مسدود یا حذف نشده باشند." +UnableToWritePath="نوشتن در%1 امکان پذیر نیست. اطمینان حاصل کنید که از یک مسیر ضبط استفاده می کنید که حساب کاربری شما مجاز به نوشتن آن است و فضای دیسک کافی وجود دارد." +WarnWindowsDefender="اگر محافظت در برابر باج افزار ویندوز 10 فعال باشد نیز می تواند باعث این خطا شود. دسترسی به پوشه کنترل شده را در امنیت ویندوز/تنظیمات محافظت در برابر تهدید خاموش کنید." +NVENC.Error="کدک NVENC باز نشد: %1" +NVENC.GenericError="بررسی کنید که درایورهای ویدیویی شما به روز هستند. سایر نرم افزارهای ضبط را که ممکن است از NVENC مانند NVIDIA Shadowplay یا DVR بازی Windows 10 استفاده کنند، ببندید." +NVENC.BadGPUIndex="شما گرافیک %1 را در تنظیمات رمزگذار خروجی خود انتخاب کرده اید. دوباره روی 0 تنظیم کنید و امتحان کنید." +NVENC.OutdatedDriver="درایور کارت ویدیویی فعلی شما از این نسخه NVENC پشتیبانی نمی کند، لطفاً درایورهای خود را به روز کنید." +NVENC.UnsupportedDevice="خطای NVENC: دستگاه پشتیبانی نمی شود. بررسی کنید کارت ویدیوی شما از NVENC پشتیبانی می کند و آیا درایورها به روز هستند." +NVENC.TooManySessions="خطای NVENC: جلسات همزمان بسیار زیاد است. سایر نرم افزارهای ضبط را که ممکن است از NVENC مانند NVIDIA Shadowplay یا DVR بازی Windows 10 استفاده کنند، ببندید." +NVENC.CheckDrivers="لطفاً به روز بودن درایورهای ویدیویی خود را بررسی کنید." +ReconnectDelayTime="تأخیر اتصال دوباره" diff --git a/plugins/obs-ffmpeg/data/locale/fil-PH.ini b/plugins/obs-ffmpeg/data/locale/fil-PH.ini index 265f569..1ee1d25 100644 --- a/plugins/obs-ffmpeg/data/locale/fil-PH.ini +++ b/plugins/obs-ffmpeg/data/locale/fil-PH.ini @@ -9,13 +9,20 @@ Lossless="Lossless" NVENC.Use2Pass="Gamitin ang Two-Pass Encoding" +NVENC.Preset.hq="Kalidad" +NVENC.Preset.hp="Pinakamalakas na Pagganap" +NVENC.Preset.mq="Pinakamalakas na Kalidad" NVENC.Preset.ll="Mababa na Latency" +NVENC.Preset.llhq="Mababang-Latency na Kalidad" +NVENC.Preset.llhp="Mababang-Latency na Pagganap" +NVENC.CQLevel="CQ na Antas" FFmpegSource="Pagkunan ng Media" LocalFile="Ang File na lokal" Looping="I-Loop" Input="Ang Input" InputFormat="Ang Format ng Input" +BufferingMB="Pag-buffer ng Network" HardwareDecode="Gamitin ang hardware decoding kapag magagamit" Advanced="I-Advanced" RestartWhenActivated="Simulan mulang ang playback kapag aktibo ang pinagmulan" @@ -43,5 +50,8 @@ ReplayBuffer.Save="I-Save ang Replay" HelperProcessFailed="Hindi pwedeng simulan ang pag proseso ng recording helper. Tingan kung OBS file ay hindi hinarangan o tinanggal ng anumang 3rd part antivirus / security software." UnableToWritePath="Hindi pwedeng sumulat sa %1. Siguraduhin na gamit ang recording path kung saan ang user account mo ay tanggap ang pagsulat at mayroon sapat na espasyo sa disk." +NVENC.OutdatedDriver="Ang iyong kasalakuyang video card driver ay hindi sinu-suporta ang itong NVENC na bersyon, mangyaring i-update ang iyong drivers." +NVENC.UnsupportedDevice="Pagkakamali ng NVENC: Hindi supportadong aparato. Tignan mo ang iyong video card kung sinu-suporta nila ang NVENC at kung yung drivers ay bago." +NVENC.CheckDrivers="Mangyaring tignan mo ang iyong video drivers kung ay bago sila." diff --git a/plugins/obs-ffmpeg/data/locale/id-ID.ini b/plugins/obs-ffmpeg/data/locale/id-ID.ini index 0fda31a..f0f1a10 100644 --- a/plugins/obs-ffmpeg/data/locale/id-ID.ini +++ b/plugins/obs-ffmpeg/data/locale/id-ID.ini @@ -31,7 +31,7 @@ Looping="Berulang" Input="Masukan" InputFormat="Format Masukan" BufferingMB="Buffering Jaringan" -HardwareDecode="Gunakan dekoder hardware jika tersedia" +HardwareDecode="Gunakan dekoder perangkat keras jika tersedia" ClearOnMediaEnd="Tidak muncul apapun saat pemutaran berakhir" Advanced="Tingkat lanjut" RestartWhenActivated="Mulai ulang pemutaran ketika sumber sudah aktif" diff --git a/plugins/obs-ffmpeg/data/locale/kab-KAB.ini b/plugins/obs-ffmpeg/data/locale/kab-KAB.ini new file mode 100644 index 0000000..6fb941b --- /dev/null +++ b/plugins/obs-ffmpeg/data/locale/kab-KAB.ini @@ -0,0 +1,53 @@ +FFmpegOutput="Tuffɣa n FFmpeg" +FFmpegAAC="Asettengal n lexṣas AAC n FFmpeg" +FFmpegOpus="Asettengal Opus n FFmpeg" +Bitrate="Aktum" +MaxBitrate="Aktum afellay" +Preset="Aseɣwer uzwir" +Profile="Amaɣnu" +RateControl="Asenqed n uktum" +KeyframeIntervalSec="Azilal n yikataren yufraren (tasinin, 0=awurman)" +Lossless="War asṛuḥu" + +BFrames="Amḍan afellay n yikataren B" + +NVENC.Use2Pass="Seqdec asettengel n sin isuka" +NVENC.Preset.default="Tamellit" +NVENC.Preset.hq="Taɣara" +NVENC.Preset.hp="Tamellit tafellayt" +NVENC.Preset.mq="Taɣara tafellayt" +NVENC.CQLevel="Aswir CQ" + +FFmpegSource="Aɣbalu amidya" +LocalFile="Afaylu adigan" +Looping="Tineddict" +Input="Anekcum" +InputFormat="Amasal n unekcum" +BufferingMB="Ajmaɛ di tkatut n uḥraz n uzeḍḍa" +HardwareDecode="Seqdec amakkas n usettengel n warrum ma yewjed" +ClearOnMediaEnd="Ur beqqeḍ acemma mi ara tfak tɣuri" +Advanced="Anaẓi" +RestartWhenActivated="Kemmel si tazwara ticki iqel uɣbalu-agi d urmid" +CloseFileWhenInactive="Mdel afaylu ticki ur yermid ara" +ColorRange="Tagrumma n yini YUV" +ColorRange.Auto="Awurman" +ColorRange.Partial="Abruyan" +ColorRange.Full="Ummid" +RestartMedia="Ales asekker" +SpeedPercentage="Arured" +Play="Taɣuri" +Pause="Bedd" +Stop="Seḥbes" + +MediaFileFilter.AllMediaFiles="Akk ifuyla imidyaten" +MediaFileFilter.VideoFiles="Ifuyla n uvidyu" +MediaFileFilter.AudioFiles="Ifuyla imeslawen" +MediaFileFilter.AllFiles="Akk ifuyla" + +ReplayBuffer="Tallunt n weḥraz n tulsa n tɣuri" +ReplayBuffer.Save="Sekles tulsa n tɣuri" + + + +ReconnectDelayTime="Amenḍar n tulsa n tɣuri" + diff --git a/plugins/obs-ffmpeg/data/locale/ko-KR.ini b/plugins/obs-ffmpeg/data/locale/ko-KR.ini index e0e37ad..9481987 100644 --- a/plugins/obs-ffmpeg/data/locale/ko-KR.ini +++ b/plugins/obs-ffmpeg/data/locale/ko-KR.ini @@ -63,8 +63,8 @@ WarnWindowsDefender="윈도우 10에서 제공하는 랜섬웨어 보호 기능 NVENC.Error="NVENC 코덱을 여는데 실패함: %1" NVENC.GenericError="드라이버가 최신 버전인지 확인하세요. NVIDIA Shadowplay 혹은 Windows 10 게임 바 캡처 기능과 같이 NVENC를 사용하고 있는 다른 녹화 프로그램을 꺼보세요." NVENC.BadGPUIndex="출력 설정 내 인코더 항목에서 GPU %1 (을)를 지정했습니다. 이 항목을 0으로 되돌린 다음 다시 시도해보세요." -NVENC.OutdatedDriver="현재 사용하고 있는 비디오 카드 드라이버가 이 NVENC 버전을 지원하지 않습니다. 드라이버를 판올림하여 주세요." -NVENC.UnsupportedDevice="NVENC 오류: 지원하지 않는 장치입니다. 비디오 카드가 NVENC를 지원하고 있고 최신 버전으로 판올림 되어 있는지 확인하여 주세요." +NVENC.OutdatedDriver="현재 사용하고 있는 비디오 카드 드라이버가 이 NVENC 버전을 지원하지 않습니다. 드라이버를 업데이트 해주세요." +NVENC.UnsupportedDevice="NVENC 오류: 지원하지 않는 장치입니다. 비디오 카드가 NVENC를 지원하고 있고 최신 버전으로 업데이트되어 있는지 확인해주세요." NVENC.TooManySessions="NVENC 오류: 너무 많은 세션을 동시에 처리하고 있습니다. NVIDIA Shadowplay 혹은 Windows 10 게임 바 캡처 기능과 같이 NVENC를 사용하고 있는 다른 녹화 프로그램을 꺼보세요." NVENC.CheckDrivers="사용 중인 그래픽 드라이버가 최신 버전인지 확인하여 주세요." diff --git a/plugins/obs-ffmpeg/data/locale/nb-NO.ini b/plugins/obs-ffmpeg/data/locale/nb-NO.ini index 76ce544..f8e1083 100644 --- a/plugins/obs-ffmpeg/data/locale/nb-NO.ini +++ b/plugins/obs-ffmpeg/data/locale/nb-NO.ini @@ -4,6 +4,7 @@ FFmpegOpus="FFmpeg Opus enkoder" Bitrate="Bitrate" MaxBitrate="Maks bitrate" Preset="Forhåndsinnstilling" +Profile="Profil" RateControl="Hastighetskontroll" KeyframeIntervalSec="Nøkkelbildeintervall (sekunder, 0 = automatisk)" Lossless="Tapsfri" @@ -67,4 +68,5 @@ NVENC.UnsupportedDevice="NVENC Error: Ustøttet enhet. Sjekk at videokortet ditt NVENC.TooManySessions="NVENC Feil: For mange samtidige økter. Prøv å lukke annen opptaksprogramvare at bruker kanskje NVENC, som NVIDIA Shadowplay eller Windows 10 Game DVR." NVENC.CheckDrivers="Vennligst sjekk at videosjåførene dine er oppdatert." +ReconnectDelayTime="Gjenoppkoblingsforsinkelse" diff --git a/plugins/obs-ffmpeg/data/locale/pt-BR.ini b/plugins/obs-ffmpeg/data/locale/pt-BR.ini index deaa0ca..fc725f5 100644 --- a/plugins/obs-ffmpeg/data/locale/pt-BR.ini +++ b/plugins/obs-ffmpeg/data/locale/pt-BR.ini @@ -26,7 +26,7 @@ NVENC.PsychoVisualTuning.ToolTip="Permite configurações do codificador que oti NVENC.CQLevel="Nível de CQ" FFmpegSource="Fonte de mídia" -LocalFile="Arquivo Local" +LocalFile="Arquivo local" Looping="Loop" Input="Entrada" InputFormat="Formato de entrada" @@ -37,7 +37,7 @@ Advanced="Avançado" RestartWhenActivated="Reiniciar reprodução quando a fonte se tornar ativa" CloseFileWhenInactive="Fechar arquivo quando inativo" CloseFileWhenInactive.ToolTip="Fechar o arquivo quando a fonte não estiver sendo exibida na transmissão\n ou gravação. Isto permite alterar o arquivo quando a fonte não está ativa,\nmas pode ter algum atraso de inicialização quando a fonte for reativada." -ColorRange="Intervalo de Cores YUV" +ColorRange="Intervalo de cores YUV" ColorRange.Auto="Auto" ColorRange.Partial="Parcial" ColorRange.Full="Completo" @@ -48,10 +48,10 @@ Play="Iniciar" Pause="Pausar" Stop="Parar" -MediaFileFilter.AllMediaFiles="Todos Arquivos de Mídia" +MediaFileFilter.AllMediaFiles="Todos os arquivos de mídia" MediaFileFilter.VideoFiles="Arquivos de Vídeo" MediaFileFilter.AudioFiles="Arquivos de Áudio" -MediaFileFilter.AllFiles="Todos os Arquivos" +MediaFileFilter.AllFiles="Todos os arquivos" ReplayBuffer="Buffer do Replay" ReplayBuffer.Save="Salvar Replay" diff --git a/plugins/obs-ffmpeg/data/locale/pt-PT.ini b/plugins/obs-ffmpeg/data/locale/pt-PT.ini index 614946b..9769fd6 100644 --- a/plugins/obs-ffmpeg/data/locale/pt-PT.ini +++ b/plugins/obs-ffmpeg/data/locale/pt-PT.ini @@ -4,6 +4,7 @@ FFmpegOpus="FFmpeg Opus Encoder" Bitrate="Bitrate" MaxBitrate="Bitrate Máximo" Preset="Predefinição" +Profile="Perfil" RateControl="Controle de Taxa" KeyframeIntervalSec="Intervalo do keyframe (segundos, 0=automático)" Lossless="Sem perdas" diff --git a/plugins/obs-ffmpeg/data/locale/ro-RO.ini b/plugins/obs-ffmpeg/data/locale/ro-RO.ini index b4c6ea0..829ebcf 100644 --- a/plugins/obs-ffmpeg/data/locale/ro-RO.ini +++ b/plugins/obs-ffmpeg/data/locale/ro-RO.ini @@ -9,7 +9,7 @@ RateControl="Controlul ratei" KeyframeIntervalSec="Interval de cadre cheie (secunde, 0=auto)" Lossless="Fără pierderi" -BFrames="Max B-frames" +BFrames="Cadre B maxime" NVENC.Use2Pass="Folosește codificarea în doi pași" NVENC.Preset.default="Performanță" @@ -19,9 +19,9 @@ NVENC.Preset.mq="Calitate maximă" NVENC.Preset.ll="Latență redusă" NVENC.Preset.llhq="Calitate cu latență redusă" NVENC.Preset.llhp="Performanță cu latență redusă" -NVENC.LookAhead="Privire" -NVENC.LookAhead.ToolTip="Activează B-frames dinamic.\n\nDacă este dezactivat, encoder-ul va utiliza întotdeauna numărul de B-frames specificat în setările 'Max B-frames'.\n\nDacă este activat, va crește calitatea vizuală utilizând doar cât de multe cadre B sunt necesare, până la maximum,\nla costul unei utilizări crescute a GPU." -NVENC.PsychoVisualTuning="Aranjare vizuală Psycho" +NVENC.LookAhead="Look-ahead" +NVENC.LookAhead.ToolTip="Activează cadre B dinamice.\n\nDacă este dezactivat, codificatorul va folosi întotdeauna numărul de cadre B specificat în setarea „Cadre B maxime”.\n\nDacă este activat, va crește calitatea vizuală folosind doar cât de multe cadre B sunt necesare, până la maximum,\ncu costul utilizării crescute a GPU-ului." +NVENC.PsychoVisualTuning="Psycho Visual Tuning" NVENC.PsychoVisualTuning.ToolTip="Activează setările de codificare care optimizează utilizarea ratei de biți pentru creșterea calității vizuale percepute,\nîn special în situații cu mișcare mare, cu prețul unei utilizări mai mari a GPU." NVENC.CQLevel="Nivel CQ" @@ -31,21 +31,21 @@ Looping="Redă în buclă" Input="Input" InputFormat="Formatul inputului" BufferingMB="Buffer Rețea" -HardwareDecode="Folosește decodarea hardware când este disponibilă" +HardwareDecode="Folosește decodificarea hardware când este disponibilă" ClearOnMediaEnd="Nu afișa nimic la terminarea redării" Advanced="Avansat" RestartWhenActivated="Repornește redarea când sursa devine activă" CloseFileWhenInactive="Închide fișierul când este inactiv" -CloseFileWhenInactive.ToolTip="Închide fișierul atunci când sursa nu este afișată pe transmisiune sau\nînregistrare. Acest lucru permite fișierului să fie schimbat în momentul în care sursa nu este activă,\nînsă poate exista o întârziere la pornire în momentul reactivării sursei." +CloseFileWhenInactive.ToolTip="Închide fișierul atunci când sursa nu este afișată pe transmisiune sau înregistrare.\nAcest lucru permite fișierului să fie schimbat în momentul în care sursa nu este\nactivă, însă poate exista o întârziere la pornire în momentul reactivării sursei." ColorRange="Gamă de culori YUV" ColorRange.Auto="Automată" ColorRange.Partial="Parțială" ColorRange.Full="Completă" RestartMedia="Repornește" SpeedPercentage="Viteză" -Seekable="Vizulizare" +Seekable="Navigabil" Play="Redare" -Pause="Pauzează" +Pause="Pune pe pauză" Stop="Stop" MediaFileFilter.AllMediaFiles="Toate fișierele media" @@ -53,17 +53,17 @@ MediaFileFilter.VideoFiles="Fișiere video" MediaFileFilter.AudioFiles="Fișiere audio" MediaFileFilter.AllFiles="Toate fișierele" -ReplayBuffer="Reluare Buffer" +ReplayBuffer="Buffer de reluări" ReplayBuffer.Save="Salvează reluarea" HelperProcessFailed="Nu se poate porni procesul ajutător de înregistrare. Verifică dacă fișierele OBS nu au fost blocate sau eliminate de orice software terț antivirus / de securitate." -UnableToWritePath="Imposibil de scris la %1. Asigurați-vă că folosiți o cale de înregistrare pe care contul dvs. de utilizator poate să o scrie și că există suficient spațiu pe disc." +UnableToWritePath="Nu se poate scrie în %1. Asigură-te că folosești o cale de înregistrare în care contul tău de utilizator are permisiunea de a scrie și că există suficient spațiu pe disc." WarnWindowsDefender="Dacă este activată protecţia Ransomware Windows 10 poate cauza şi această eroare. Încercați să dezactivați accesul la dosarele controlate în setările de securitate / Virus și protecție împotriva amenințării." NVENC.Error="Deschiderea codecului NVENC a eșuat: %1" NVENC.GenericError="Verifică dacă driverele video sunt actualizate. Încercați să închideți alte programe de înregistrare care ar putea utiliza NVENC, cum ar fi NVIDIA Shadowplay sau Windows 10 Game DVR." NVENC.BadGPUIndex="Ai selectat GPU-ul %1 în setările codificatorului de output. Setează acest lucru înapoi la 0 și încearcă din nou." -NVENC.OutdatedDriver="Driver-ul dvs. actual de pe cardul video nu acceptă această versiune NVENC, vă rugăm să vă actualizați driverele." +NVENC.OutdatedDriver="Driverul actual al plăcii tale video nu suportă această versiune NVENC, te rugăm să actualizezi driverele." NVENC.UnsupportedDevice="Eroare NVENC. Dispozitivul nu este acceptat. Verificați dacă cardul video suportă NVENC și dacă driverele sunt actualizate." NVENC.TooManySessions="Eroare NVENC: Prea multe sesiuni concurente. Încercați să închideți alte programe de înregistrare care ar putea folosi NVENC, cum ar fi NVIDIA Shadowplay sau Windows 10 Game DVR." NVENC.CheckDrivers="Te rugăm să verifici dacă driverele video sunt actualizate." diff --git a/plugins/obs-ffmpeg/data/locale/sl-SI.ini b/plugins/obs-ffmpeg/data/locale/sl-SI.ini index 609a2b4..abf3784 100644 --- a/plugins/obs-ffmpeg/data/locale/sl-SI.ini +++ b/plugins/obs-ffmpeg/data/locale/sl-SI.ini @@ -4,6 +4,7 @@ FFmpegOpus="Kodirnik Opus FFmpeg" Bitrate="Bitna hitrost" MaxBitrate="Največja bitna hitrost" Preset="Prednastavitev" +Profile="Profil" RateControl="Nadzor hitrosti" KeyframeIntervalSec="Razmik med ključnimi sličicami (ssekunde, 0=samodejno)" Lossless="Brezizgubno" diff --git a/plugins/obs-ffmpeg/data/locale/sv-SE.ini b/plugins/obs-ffmpeg/data/locale/sv-SE.ini index 67f05a8..d14f1c9 100644 --- a/plugins/obs-ffmpeg/data/locale/sv-SE.ini +++ b/plugins/obs-ffmpeg/data/locale/sv-SE.ini @@ -31,7 +31,7 @@ Looping="Upprepa" Input="Infoga" InputFormat="Inmatningsformat" BufferingMB="Nätverksbuffring" -HardwareDecode="Använda hårdvareavkodning när tillgängligt" +HardwareDecode="Använd hårdvaruavkodning när det är tillgängligt" ClearOnMediaEnd="Visa ingenting när uppspelningen slutar" Advanced="Avancerat" RestartWhenActivated="Starta om uppspelning när källa blir aktiv" diff --git a/plugins/obs-ffmpeg/data/locale/vi-VN.ini b/plugins/obs-ffmpeg/data/locale/vi-VN.ini index 2c4c4a8..3d51c63 100644 --- a/plugins/obs-ffmpeg/data/locale/vi-VN.ini +++ b/plugins/obs-ffmpeg/data/locale/vi-VN.ini @@ -1,5 +1,6 @@ FFmpegOutput="FFmpeg đầu ra" FFmpegAAC="FFmpeg AAC Encoder mặc định" +FFmpegOpus="Bộ mã hóa FFmpeg Opus" Bitrate="Bitrate" MaxBitrate="'Tốc độ bit' tối đa" Preset="Mẫu thiết lập" @@ -8,6 +9,7 @@ RateControl="Cách kiểm soát bitrate" KeyframeIntervalSec="Thời gian đặt Keyframe (giây, 0=tự động)" Lossless="Lossless" +BFrames="Khung-B tối đa" NVENC.Use2Pass="Sử dụng 2-Pass Encoding" NVENC.Preset.default="Hiệu suất" @@ -17,6 +19,7 @@ NVENC.Preset.mq="Chất lượng tối đa" NVENC.Preset.ll="Độ trễ thấp" NVENC.Preset.llhq="Chất lượng \"độ trễ thấp\"" NVENC.Preset.llhp="Hiệu suất \"độ trễ thấp\"" +NVENC.LookAhead="Look-ahead" FFmpegSource="Nguồn media" LocalFile="Tập tin cục bộ" diff --git a/plugins/obs-ffmpeg/ffmpeg-mux/CMakeLists.txt b/plugins/obs-ffmpeg/ffmpeg-mux/CMakeLists.txt index c886ac6..754a1ab 100644 --- a/plugins/obs-ffmpeg/ffmpeg-mux/CMakeLists.txt +++ b/plugins/obs-ffmpeg/ffmpeg-mux/CMakeLists.txt @@ -1,5 +1,9 @@ project(obs-ffmpeg-mux) +if(DEBUG_FFMPEG_MUX) + add_definitions(-DDEBUG_FFMPEG) +endif() + find_package(FFmpeg REQUIRED COMPONENTS avcodec avutil avformat) include_directories(${FFMPEG_INCLUDE_DIRS}) @@ -15,6 +19,7 @@ add_executable(obs-ffmpeg-mux ${obs-ffmpeg-mux_HEADERS}) target_link_libraries(obs-ffmpeg-mux + libobs ${FFMPEG_LIBRARIES}) set_target_properties(obs-ffmpeg-mux PROPERTIES FOLDER "plugins/obs-ffmpeg") diff --git a/plugins/obs-ffmpeg/ffmpeg-mux/ffmpeg-mux.c b/plugins/obs-ffmpeg/ffmpeg-mux/ffmpeg-mux.c index 8b9c0f2..debe646 100644 --- a/plugins/obs-ffmpeg/ffmpeg-mux/ffmpeg-mux.c +++ b/plugins/obs-ffmpeg/ffmpeg-mux/ffmpeg-mux.c @@ -22,13 +22,17 @@ #endif -#include #include #include #include "ffmpeg-mux.h" +#include #include +#define ANSI_COLOR_RED "\x1b[0;91m" +#define ANSI_COLOR_MAGENTA "\x1b[0;95m" +#define ANSI_COLOR_RESET "\x1b[0m" + #if LIBAVCODEC_VERSION_MAJOR >= 58 #define CODEC_FLAG_GLOBAL_H AV_CODEC_FLAG_GLOBAL_HEADER #else @@ -37,6 +41,8 @@ /* ------------------------------------------------------------------------- */ +static char *global_stream_key = ""; + struct resize_buf { uint8_t *buf; size_t size; @@ -70,6 +76,8 @@ static inline void resize_buf_free(struct resize_buf *rb) struct main_params { char *file; + /* printable_file is file with any stream key information removed */ + struct dstr printable_file; int has_video; int tracks; char *vcodec; @@ -172,6 +180,8 @@ static void ffmpeg_mux_free(struct ffmpeg_mux *ffm) free(ffm->audio); } + dstr_free(&ffm->params.printable_file); + memset(ffm, 0, sizeof(*ffm)); } @@ -218,6 +228,44 @@ static bool get_audio_params(struct audio_params *audio, int *argc, return true; } +static void ffmpeg_log_callback(void *param, int level, const char *format, + va_list args) +{ +#ifdef DEBUG_FFMPEG + char out_buffer[4096]; + struct dstr out = {0}; + + vsnprintf(out_buffer, sizeof(out_buffer), format, args); + dstr_copy(&out, out_buffer); + dstr_replace(&out, global_stream_key, "{stream_key}"); + + switch (level) { + case AV_LOG_INFO: + fprintf(stdout, "info: [ffmpeg_muxer] %s", out.array); + fflush(stdout); + break; + + case AV_LOG_WARNING: + fprintf(stdout, "%swarning: [ffmpeg_muxer] %s%s", + ANSI_COLOR_MAGENTA, out.array, ANSI_COLOR_RESET); + fflush(stdout); + break; + + case AV_LOG_ERROR: + fprintf(stderr, "%serror: [ffmpeg_muxer] %s%s", ANSI_COLOR_RED, + out.array, ANSI_COLOR_RESET); + fflush(stderr); + } + + dstr_free(&out); +#else + UNUSED_PARAMETER(level); + UNUSED_PARAMETER(format); + UNUSED_PARAMETER(args); +#endif + UNUSED_PARAMETER(param); +} + static bool init_params(int *argc, char ***argv, struct main_params *params, struct audio_params **p_audio) { @@ -287,6 +335,16 @@ static bool init_params(int *argc, char ***argv, struct main_params *params, *p_audio = audio; + dstr_copy(¶ms->printable_file, params->file); + + get_opt_str(argc, argv, &global_stream_key, "stream key"); + if (strcmp(global_stream_key, "") != 0) { + dstr_replace(¶ms->printable_file, global_stream_key, + "{stream_key}"); + } + + av_log_set_callback(ffmpeg_log_callback); + get_opt_str(argc, argv, ¶ms->muxer_settings, "muxer settings"); return true; @@ -353,6 +411,10 @@ static void create_video_stream(struct ffmpeg_mux *ffm) (AVRational){ffm->params.fps_den, ffm->params.fps_num}; ffm->video_stream->time_base = context->time_base; +#if LIBAVFORMAT_VERSION_MAJOR < 59 + // codec->time_base may still be used if LIBAVFORMAT_VERSION_MAJOR < 59 + ffm->video_stream->codec->time_base = context->time_base; +#endif ffm->video_stream->avg_frame_rate = av_inv_q(context->time_base); if (ffm->output->oformat->flags & AVFMT_GLOBALHEADER) @@ -521,7 +583,8 @@ static inline int open_output_file(struct ffmpeg_mux *ffm) AVIO_FLAG_WRITE); if (ret < 0) { fprintf(stderr, "Couldn't open '%s', %s\n", - ffm->params.file, av_err2str(ret)); + ffm->params.printable_file.array, + av_err2str(ret)); return FFM_ERROR; } } @@ -548,8 +611,8 @@ static inline int open_output_file(struct ffmpeg_mux *ffm) ret = avformat_write_header(ffm->output, &dict); if (ret < 0) { - fprintf(stderr, "Error opening '%s': %s\n", ffm->params.file, - av_err2str(ret)); + fprintf(stderr, "Error opening '%s': %s", + ffm->params.printable_file.array, av_err2str(ret)); av_dict_free(&dict); @@ -564,29 +627,43 @@ static inline int open_output_file(struct ffmpeg_mux *ffm) #define SRT_PROTO "srt" #define UDP_PROTO "udp" #define TCP_PROTO "tcp" +#define HTTP_PROTO "http" + +static bool ffmpeg_mux_is_network(struct ffmpeg_mux *ffm) +{ + return !strncmp(ffm->params.file, SRT_PROTO, sizeof(SRT_PROTO) - 1) || + !strncmp(ffm->params.file, UDP_PROTO, sizeof(UDP_PROTO) - 1) || + !strncmp(ffm->params.file, TCP_PROTO, sizeof(TCP_PROTO) - 1) || + !strncmp(ffm->params.file, HTTP_PROTO, sizeof(HTTP_PROTO) - 1); +} static int ffmpeg_mux_init_context(struct ffmpeg_mux *ffm) { AVOutputFormat *output_format; int ret; - bool isNetwork = false; - if (strncmp(ffm->params.file, SRT_PROTO, sizeof(SRT_PROTO) - 1) == 0 || - strncmp(ffm->params.file, UDP_PROTO, sizeof(UDP_PROTO) - 1) == 0 || - strncmp(ffm->params.file, TCP_PROTO, sizeof(TCP_PROTO) - 1) == 0) - isNetwork = true; + bool is_http = false; + is_http = (strncmp(ffm->params.file, HTTP_PROTO, + sizeof(HTTP_PROTO) - 1) == 0); - if (isNetwork) { + bool is_network = ffmpeg_mux_is_network(ffm); + + if (is_network) { avformat_network_init(); - output_format = av_guess_format("mpegts", NULL, "video/M2PT"); - } else { - output_format = av_guess_format(NULL, ffm->params.file, NULL); } + if (is_network && !is_http) + output_format = av_guess_format("mpegts", NULL, "video/M2PT"); + else + output_format = av_guess_format(NULL, ffm->params.file, NULL); + if (output_format == NULL) { fprintf(stderr, "Couldn't find an appropriate muxer for '%s'\n", - ffm->params.file); + ffm->params.printable_file.array); return FFM_ERROR; } + printf("info: Output format name and long_name: %s, %s\n", + output_format->name ? output_format->name : "unknown", + output_format->long_name ? output_format->long_name : "unknown"); ret = avformat_alloc_output_context2(&ffm->output, output_format, NULL, ffm->params.file); @@ -726,8 +803,13 @@ static inline bool ffmpeg_mux_packet(struct ffmpeg_mux *ffm, uint8_t *buf, int ret = av_interleaved_write_frame(ffm->output, &packet); if (ret < 0) { - fprintf(stderr, "av_interleaved_write_frame failed: %s\n", - av_err2str(ret)); + fprintf(stderr, "av_interleaved_write_frame failed: %d: %s\n", + ret, av_err2str(ret)); + } + + /* Treat "Invalid data found when processing input" and "Invalid argument" as non-fatal */ + if (ret == AVERROR_INVALIDDATA || ret == EINVAL) { + return true; } return ret >= 0; diff --git a/plugins/obs-ffmpeg/ffmpeg-mux/ffmpeg-mux.h b/plugins/obs-ffmpeg/ffmpeg-mux/ffmpeg-mux.h index 9f7788f..ac3bc77 100644 --- a/plugins/obs-ffmpeg/ffmpeg-mux/ffmpeg-mux.h +++ b/plugins/obs-ffmpeg/ffmpeg-mux/ffmpeg-mux.h @@ -16,6 +16,7 @@ #pragma once +#include #include enum ffm_packet_type { diff --git a/plugins/obs-ffmpeg/jim-nvenc.c b/plugins/obs-ffmpeg/jim-nvenc.c index 1713e32..9cfad89 100644 --- a/plugins/obs-ffmpeg/jim-nvenc.c +++ b/plugins/obs-ffmpeg/jim-nvenc.c @@ -426,6 +426,14 @@ static bool init_encoder(struct nvenc_data *enc, obs_data_t *settings) config->gopLength = gop_size; config->frameIntervalP = 1 + bf; h264_config->idrPeriod = gop_size; + + bool repeat_headers = obs_data_get_bool(settings, "repeat_headers"); + if (repeat_headers) { + h264_config->repeatSPSPPS = 1; + h264_config->disableSPSPPS = 0; + h264_config->outputAUD = 1; + } + vui_params->videoSignalTypePresentFlag = 1; vui_params->videoFullRangeFlag = (voi->range == VIDEO_RANGE_FULL); vui_params->colourDescriptionPresentFlag = 1; diff --git a/plugins/obs-ffmpeg/obs-ffmpeg-hls-mux.c b/plugins/obs-ffmpeg/obs-ffmpeg-hls-mux.c new file mode 100644 index 0000000..9093a57 --- /dev/null +++ b/plugins/obs-ffmpeg/obs-ffmpeg-hls-mux.c @@ -0,0 +1,332 @@ +#include "obs-ffmpeg-mux.h" + +#define do_log(level, format, ...) \ + blog(level, "[ffmpeg hls muxer: '%s'] " format, \ + obs_output_get_name(stream->output), ##__VA_ARGS__) + +#define warn(format, ...) do_log(LOG_WARNING, format, ##__VA_ARGS__) +#define info(format, ...) do_log(LOG_INFO, format, ##__VA_ARGS__) + +const char *ffmpeg_hls_mux_getname(void *type) +{ + UNUSED_PARAMETER(type); + return obs_module_text("FFmpegHlsMuxer"); +} + +int hls_stream_dropped_frames(void *data) +{ + struct ffmpeg_muxer *stream = data; + return stream->dropped_frames; +} + +void ffmpeg_hls_mux_destroy(void *data) +{ + struct ffmpeg_muxer *stream = data; + + if (stream) { + deactivate(stream, 0); + + pthread_mutex_destroy(&stream->write_mutex); + os_sem_destroy(stream->write_sem); + os_event_destroy(stream->stop_event); + + da_free(stream->mux_packets); + circlebuf_free(&stream->packets); + + os_process_pipe_destroy(stream->pipe); + dstr_free(&stream->path); + dstr_free(&stream->printable_path); + dstr_free(&stream->stream_key); + dstr_free(&stream->muxer_settings); + bfree(data); + } +} + +void *ffmpeg_hls_mux_create(obs_data_t *settings, obs_output_t *output) +{ + struct ffmpeg_muxer *stream = bzalloc(sizeof(*stream)); + pthread_mutex_init_value(&stream->write_mutex); + stream->output = output; + + /* init mutex, semaphore and event */ + if (pthread_mutex_init(&stream->write_mutex, NULL) != 0) + goto fail; + if (os_event_init(&stream->stop_event, OS_EVENT_TYPE_AUTO) != 0) + goto fail; + if (os_sem_init(&stream->write_sem, 0) != 0) + goto fail; + + UNUSED_PARAMETER(settings); + return stream; + +fail: + ffmpeg_hls_mux_destroy(stream); + return NULL; +} + +static bool process_packet(struct ffmpeg_muxer *stream) +{ + struct encoder_packet packet; + bool has_packet = false; + bool ret = true; + + pthread_mutex_lock(&stream->write_mutex); + + if (stream->packets.size) { + circlebuf_pop_front(&stream->packets, &packet, sizeof(packet)); + has_packet = true; + } + + pthread_mutex_unlock(&stream->write_mutex); + + if (has_packet) { + ret = write_packet(stream, &packet); + obs_encoder_packet_release(&packet); + } + return ret; +} + +static void *write_thread(void *data) +{ + struct ffmpeg_muxer *stream = data; + + while (os_sem_wait(stream->write_sem) == 0) { + if (os_event_try(stream->stop_event) == 0) + return NULL; + + if (!process_packet(stream)) + break; + } + + obs_output_signal_stop(stream->output, OBS_OUTPUT_ERROR); + deactivate(stream, 0); + return NULL; +} + +bool ffmpeg_hls_mux_start(void *data) +{ + struct ffmpeg_muxer *stream = data; + obs_service_t *service; + const char *path_str; + const char *stream_key; + struct dstr path = {0}; + obs_encoder_t *vencoder; + obs_data_t *settings; + int keyint_sec; + + if (!obs_output_can_begin_data_capture(stream->output, 0)) + return false; + if (!obs_output_initialize_encoders(stream->output, 0)) + return false; + + service = obs_output_get_service(stream->output); + if (!service) + return false; + path_str = obs_service_get_url(service); + stream_key = obs_service_get_key(service); + dstr_copy(&stream->stream_key, stream_key); + dstr_copy(&path, path_str); + dstr_replace(&path, "{stream_key}", stream_key); + dstr_copy(&stream->muxer_settings, + "method=PUT http_persistent=1 ignore_io_errors=1 "); + dstr_catf(&stream->muxer_settings, "http_user_agent=libobs/%s", + OBS_VERSION); + + vencoder = obs_output_get_video_encoder(stream->output); + settings = obs_encoder_get_settings(vencoder); + keyint_sec = (int)obs_data_get_int(settings, "keyint_sec"); + if (keyint_sec) { + dstr_catf(&stream->muxer_settings, " hls_time=%d", keyint_sec); + stream->keyint_sec = keyint_sec; + } + + obs_data_release(settings); + + start_pipe(stream, path.array); + dstr_free(&path); + + if (!stream->pipe) { + obs_output_set_last_error( + stream->output, obs_module_text("HelperProcessFailed")); + warn("Failed to create process pipe"); + return false; + } + stream->mux_thread_joinable = pthread_create(&stream->mux_thread, NULL, + write_thread, stream) == 0; + if (!stream->mux_thread_joinable) + return false; + + /* write headers and start capture */ + os_atomic_set_bool(&stream->active, true); + os_atomic_set_bool(&stream->capturing, true); + stream->is_hls = true; + stream->total_bytes = 0; + stream->dropped_frames = 0; + stream->min_priority = 0; + + obs_output_begin_data_capture(stream->output, 0); + + dstr_copy(&stream->printable_path, path_str); + info("Writing to path '%s'...", stream->printable_path.array); + return true; +} + +static bool write_packet_to_buf(struct ffmpeg_muxer *stream, + struct encoder_packet *packet) +{ + circlebuf_push_back(&stream->packets, packet, + sizeof(struct encoder_packet)); + return true; +} + +static void drop_frames(struct ffmpeg_muxer *stream, int highest_priority) +{ + struct circlebuf new_buf = {0}; + int num_frames_dropped = 0; + + circlebuf_reserve(&new_buf, sizeof(struct encoder_packet) * 8); + + while (stream->packets.size) { + struct encoder_packet packet; + circlebuf_pop_front(&stream->packets, &packet, sizeof(packet)); + + /* do not drop audio data or video keyframes */ + if (packet.type == OBS_ENCODER_AUDIO || + packet.drop_priority >= highest_priority) { + circlebuf_push_back(&new_buf, &packet, sizeof(packet)); + } else { + num_frames_dropped++; + obs_encoder_packet_release(&packet); + } + } + + circlebuf_free(&stream->packets); + stream->packets = new_buf; + + if (stream->min_priority < highest_priority) + stream->min_priority = highest_priority; + + stream->dropped_frames += num_frames_dropped; +} + +static bool find_first_video_packet(struct ffmpeg_muxer *stream, + struct encoder_packet *first) +{ + size_t count = stream->packets.size / sizeof(*first); + + for (size_t i = 0; i < count; i++) { + struct encoder_packet *cur = + circlebuf_data(&stream->packets, i * sizeof(*first)); + if (cur->type == OBS_ENCODER_VIDEO && !cur->keyframe) { + *first = *cur; + return true; + } + } + return false; +} + +void check_to_drop_frames(struct ffmpeg_muxer *stream, bool pframes) +{ + struct encoder_packet first; + int64_t buffer_duration_usec; + int priority = pframes ? OBS_NAL_PRIORITY_HIGHEST + : OBS_NAL_PRIORITY_HIGH; + int keyint_sec = stream->keyint_sec; + int64_t drop_threshold_sec = keyint_sec ? 2 * keyint_sec : 10; + + if (!find_first_video_packet(stream, &first)) + return; + + buffer_duration_usec = stream->last_dts_usec - first.dts_usec; + + if (buffer_duration_usec > drop_threshold_sec * 1000000) + drop_frames(stream, priority); +} + +static bool add_video_packet(struct ffmpeg_muxer *stream, + struct encoder_packet *packet) +{ + check_to_drop_frames(stream, false); + check_to_drop_frames(stream, true); + + /* if currently dropping frames, drop packets until it reaches the + * desired priority */ + if (packet->drop_priority < stream->min_priority) { + stream->dropped_frames++; + return false; + } else { + stream->min_priority = 0; + } + + stream->last_dts_usec = packet->dts_usec; + return write_packet_to_buf(stream, packet); +} + +void ffmpeg_hls_mux_data(void *data, struct encoder_packet *packet) +{ + struct ffmpeg_muxer *stream = data; + struct encoder_packet new_packet; + struct encoder_packet tmp_packet; + bool added_packet = false; + + if (!active(stream)) + return; + + /* encoder failure */ + if (!packet) { + deactivate(stream, OBS_OUTPUT_ENCODE_ERROR); + return; + } + + if (!stream->sent_headers) { + if (!send_headers(stream)) + return; + stream->sent_headers = true; + } + + if (stopping(stream)) { + if (packet->sys_dts_usec >= stream->stop_ts) { + deactivate(stream, 0); + return; + } + } + + if (packet->type == OBS_ENCODER_VIDEO) { + obs_parse_avc_packet(&tmp_packet, packet); + packet->drop_priority = tmp_packet.priority; + obs_encoder_packet_release(&tmp_packet); + } + obs_encoder_packet_ref(&new_packet, packet); + + pthread_mutex_lock(&stream->write_mutex); + + if (active(stream)) { + added_packet = + (packet->type == OBS_ENCODER_VIDEO) + ? add_video_packet(stream, &new_packet) + : write_packet_to_buf(stream, &new_packet); + } + + pthread_mutex_unlock(&stream->write_mutex); + + if (added_packet) + os_sem_post(stream->write_sem); + else + obs_encoder_packet_release(&new_packet); +} + +struct obs_output_info ffmpeg_hls_muxer = { + .id = "ffmpeg_hls_muxer", + .flags = OBS_OUTPUT_AV | OBS_OUTPUT_ENCODED | OBS_OUTPUT_MULTI_TRACK | + OBS_OUTPUT_SERVICE, + .encoded_video_codecs = "h264", + .encoded_audio_codecs = "aac", + .get_name = ffmpeg_hls_mux_getname, + .create = ffmpeg_hls_mux_create, + .destroy = ffmpeg_hls_mux_destroy, + .start = ffmpeg_hls_mux_start, + .stop = ffmpeg_mux_stop, + .encoded_packet = ffmpeg_hls_mux_data, + .get_total_bytes = ffmpeg_mux_total_bytes, + .get_dropped_frames = hls_stream_dropped_frames, +}; diff --git a/plugins/obs-ffmpeg/obs-ffmpeg-mux.c b/plugins/obs-ffmpeg/obs-ffmpeg-mux.c index 7107c4e..83f04b6 100644 --- a/plugins/obs-ffmpeg/obs-ffmpeg-mux.c +++ b/plugins/obs-ffmpeg/obs-ffmpeg-mux.c @@ -14,17 +14,8 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . ******************************************************************************/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include #include "ffmpeg-mux/ffmpeg-mux.h" +#include "obs-ffmpeg-mux.h" #ifdef _WIN32 #include "util/windows/win-version.h" @@ -39,35 +30,6 @@ #define warn(format, ...) do_log(LOG_WARNING, format, ##__VA_ARGS__) #define info(format, ...) do_log(LOG_INFO, format, ##__VA_ARGS__) -struct ffmpeg_muxer { - obs_output_t *output; - os_process_pipe_t *pipe; - int64_t stop_ts; - uint64_t total_bytes; - struct dstr path; - bool sent_headers; - volatile bool active; - volatile bool stopping; - volatile bool capturing; - - /* replay buffer */ - struct circlebuf packets; - int64_t cur_size; - int64_t cur_time; - int64_t max_size; - int64_t max_time; - int64_t save_ts; - int keyframes; - obs_hotkey_id hotkey; - - DARRAY(struct encoder_packet) mux_packets; - pthread_t mux_thread; - bool mux_thread_joinable; - volatile bool muxing; - - bool is_network; -}; - static const char *ffmpeg_mux_getname(void *type) { UNUSED_PARAMETER(type); @@ -105,9 +67,13 @@ static void ffmpeg_mux_destroy(void *data) if (stream->mux_thread_joinable) pthread_join(stream->mux_thread, NULL); da_free(stream->mux_packets); + circlebuf_free(&stream->packets); os_process_pipe_destroy(stream->pipe); dstr_free(&stream->path); + dstr_free(&stream->printable_path); + dstr_free(&stream->stream_key); + dstr_free(&stream->muxer_settings); bfree(stream); } @@ -134,12 +100,12 @@ static inline bool capturing(struct ffmpeg_muxer *stream) return os_atomic_load_bool(&stream->capturing); } -static inline bool stopping(struct ffmpeg_muxer *stream) +bool stopping(struct ffmpeg_muxer *stream) { return os_atomic_load_bool(&stream->stopping); } -static inline bool active(struct ffmpeg_muxer *stream) +bool active(struct ffmpeg_muxer *stream) { return os_atomic_load_bool(&stream->active); } @@ -236,17 +202,30 @@ static void log_muxer_params(struct ffmpeg_muxer *stream, const char *settings) av_dict_free(&dict); } +static void add_stream_key(struct dstr *cmd, struct ffmpeg_muxer *stream) +{ + dstr_catf(cmd, "\"%s\" ", + dstr_is_empty(&stream->stream_key) + ? "" + : stream->stream_key.array); +} + static void add_muxer_params(struct dstr *cmd, struct ffmpeg_muxer *stream) { - obs_data_t *settings = obs_output_get_settings(stream->output); struct dstr mux = {0}; - dstr_copy(&mux, obs_data_get_string(settings, "muxer_settings")); + if (dstr_is_empty(&stream->muxer_settings)) { + obs_data_t *settings = obs_output_get_settings(stream->output); + dstr_copy(&mux, + obs_data_get_string(settings, "muxer_settings")); + obs_data_release(settings); + } else { + dstr_copy(&mux, stream->muxer_settings.array); + } log_muxer_params(stream, mux.array); dstr_replace(&mux, "\"", "\\\""); - obs_data_release(settings); dstr_catf(cmd, "\"%s\" ", mux.array ? mux.array : ""); @@ -291,10 +270,11 @@ static void build_command_line(struct ffmpeg_muxer *stream, struct dstr *cmd, } } + add_stream_key(cmd, stream); add_muxer_params(cmd, stream); } -static inline void start_pipe(struct ffmpeg_muxer *stream, const char *path) +void start_pipe(struct ffmpeg_muxer *stream, const char *path) { struct dstr cmd; build_command_line(stream, &cmd, path); @@ -381,10 +361,19 @@ static bool ffmpeg_mux_start(void *data) return true; } -static int deactivate(struct ffmpeg_muxer *stream, int code) +int deactivate(struct ffmpeg_muxer *stream, int code) { int ret = -1; + if (stream->is_hls) { + if (stream->mux_thread_joinable) { + os_event_signal(stream->stop_event); + os_sem_post(stream->write_sem); + pthread_join(stream->mux_thread, NULL); + stream->mux_thread_joinable = false; + } + } + if (active(stream)) { ret = os_process_pipe_destroy(stream->pipe); stream->pipe = NULL; @@ -392,7 +381,10 @@ static int deactivate(struct ffmpeg_muxer *stream, int code) os_atomic_set_bool(&stream->active, false); os_atomic_set_bool(&stream->sent_headers, false); - info("Output of file '%s' stopped", stream->path.array); + info("Output of file '%s' stopped", + dstr_is_empty(&stream->printable_path) + ? stream->path.array + : stream->printable_path.array); } if (code) { @@ -401,11 +393,24 @@ static int deactivate(struct ffmpeg_muxer *stream, int code) obs_output_end_data_capture(stream->output); } + if (stream->is_hls) { + pthread_mutex_lock(&stream->write_mutex); + + while (stream->packets.size) { + struct encoder_packet packet; + circlebuf_pop_front(&stream->packets, &packet, + sizeof(packet)); + obs_encoder_packet_release(&packet); + } + + pthread_mutex_unlock(&stream->write_mutex); + } + os_atomic_set_bool(&stream->stopping, false); return ret; } -static void ffmpeg_mux_stop(void *data, uint64_t ts) +void ffmpeg_mux_stop(void *data, uint64_t ts) { struct ffmpeg_muxer *stream = data; @@ -451,8 +456,7 @@ static void signal_failure(struct ffmpeg_muxer *stream) os_atomic_set_bool(&stream->capturing, false); } -static bool write_packet(struct ffmpeg_muxer *stream, - struct encoder_packet *packet) +bool write_packet(struct ffmpeg_muxer *stream, struct encoder_packet *packet) { bool is_video = packet->type == OBS_ENCODER_VIDEO; size_t ret; @@ -505,7 +509,7 @@ static bool send_video_headers(struct ffmpeg_muxer *stream) return write_packet(stream, &packet); } -static bool send_headers(struct ffmpeg_muxer *stream) +bool send_headers(struct ffmpeg_muxer *stream) { obs_encoder_t *aencoder; size_t idx = 0; @@ -567,7 +571,7 @@ static obs_properties_t *ffmpeg_mux_properties(void *unused) return props; } -static uint64_t ffmpeg_mux_total_bytes(void *data) +uint64_t ffmpeg_mux_total_bytes(void *data) { struct ffmpeg_muxer *stream = data; return stream->total_bytes; @@ -646,6 +650,12 @@ static void replay_buffer_hotkey(void *data, obs_hotkey_id id, return; } + calldata_t cd = {0}; + + signal_handler_t *sh = + obs_output_get_signal_handler(stream->output); + signal_handler_signal(sh, "saved", &cd); + stream->save_ts = os_gettime_ns() / 1000LL; } } @@ -679,6 +689,9 @@ static void *replay_buffer_create(obs_data_t *settings, obs_output_t *output) proc_handler_add(ph, "void get_last_replay(out string path)", get_last_replay, stream); + signal_handler_t *sh = obs_output_get_signal_handler(output); + signal_handler_add(sh, "void saved()"); + return stream; } diff --git a/plugins/obs-ffmpeg/obs-ffmpeg-mux.h b/plugins/obs-ffmpeg/obs-ffmpeg-mux.h new file mode 100644 index 0000000..eb9dbe1 --- /dev/null +++ b/plugins/obs-ffmpeg/obs-ffmpeg-mux.h @@ -0,0 +1,63 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct ffmpeg_muxer { + obs_output_t *output; + os_process_pipe_t *pipe; + int64_t stop_ts; + uint64_t total_bytes; + bool sent_headers; + volatile bool active; + volatile bool capturing; + volatile bool stopping; + struct dstr path; + struct dstr printable_path; + struct dstr muxer_settings; + struct dstr stream_key; + + /* replay buffer */ + int64_t cur_size; + int64_t cur_time; + int64_t max_size; + int64_t max_time; + int64_t save_ts; + int keyframes; + obs_hotkey_id hotkey; + volatile bool muxing; + DARRAY(struct encoder_packet) mux_packets; + + /* these are accessed both by replay buffer and by HLS */ + pthread_t mux_thread; + bool mux_thread_joinable; + struct circlebuf packets; + + /* HLS only */ + int keyint_sec; + pthread_mutex_t write_mutex; + os_sem_t *write_sem; + os_event_t *stop_event; + bool is_hls; + int dropped_frames; + int min_priority; + int64_t last_dts_usec; + + bool is_network; +}; + +bool stopping(struct ffmpeg_muxer *stream); +bool active(struct ffmpeg_muxer *stream); +void start_pipe(struct ffmpeg_muxer *stream, const char *path); +bool write_packet(struct ffmpeg_muxer *stream, struct encoder_packet *packet); +bool send_headers(struct ffmpeg_muxer *stream); +int deactivate(struct ffmpeg_muxer *stream, int code); +void ffmpeg_mux_stop(void *data, uint64_t ts); +uint64_t ffmpeg_mux_total_bytes(void *data); diff --git a/plugins/obs-ffmpeg/obs-ffmpeg-nvenc.c b/plugins/obs-ffmpeg/obs-ffmpeg-nvenc.c index 24b8a7c..cc17b25 100644 --- a/plugins/obs-ffmpeg/obs-ffmpeg-nvenc.c +++ b/plugins/obs-ffmpeg/obs-ffmpeg-nvenc.c @@ -477,6 +477,7 @@ void nvenc_defaults(obs_data_t *settings) obs_data_set_default_bool(settings, "psycho_aq", true); obs_data_set_default_int(settings, "gpu", 0); obs_data_set_default_int(settings, "bf", 2); + obs_data_set_default_bool(settings, "repeat_headers", false); } static bool rate_control_modified(obs_properties_t *ppts, obs_property_t *p, @@ -576,6 +577,9 @@ obs_properties_t *nvenc_properties_internal(bool ffmpeg) obs_module_text("NVENC.PsychoVisualTuning")); obs_property_set_long_description( p, obs_module_text("NVENC.PsychoVisualTuning.ToolTip")); + p = obs_properties_add_bool(props, "repeat_headers", + "repeat_headers"); + obs_property_set_visible(p, false); } obs_properties_add_int(props, "gpu", obs_module_text("GPU"), 0, 8, 1); diff --git a/plugins/obs-ffmpeg/obs-ffmpeg.c b/plugins/obs-ffmpeg/obs-ffmpeg.c index 38a7c85..b7a1709 100644 --- a/plugins/obs-ffmpeg/obs-ffmpeg.c +++ b/plugins/obs-ffmpeg/obs-ffmpeg.c @@ -24,6 +24,7 @@ extern struct obs_output_info ffmpeg_output; extern struct obs_output_info ffmpeg_muxer; extern struct obs_output_info ffmpeg_mpegts_muxer; extern struct obs_output_info replay_buffer; +extern struct obs_output_info ffmpeg_hls_muxer; extern struct obs_encoder_info aac_encoder_info; extern struct obs_encoder_info opus_encoder_info; extern struct obs_encoder_info nvenc_encoder_info; @@ -81,6 +82,7 @@ static const int blacklisted_adapters[] = { 0x1d11, // GP108M [GeForce MX230] 0x1d13, // GP108M [GeForce MX250] 0x1d52, // GP108BM [GeForce MX250] + 0x1c94, // GP107 [GeForce MX350] 0x137b, // GM108GLM [Quadro M520 Mobile] 0x1d33, // GP108GLM [Quadro P500 Mobile] 0x137a, // GM108GLM [Quadro K620M / Quadro M500M] @@ -231,6 +233,7 @@ bool obs_module_load(void) obs_register_output(&ffmpeg_output); obs_register_output(&ffmpeg_muxer); obs_register_output(&ffmpeg_mpegts_muxer); + obs_register_output(&ffmpeg_hls_muxer); obs_register_output(&replay_buffer); obs_register_encoder(&aac_encoder_info); obs_register_encoder(&opus_encoder_info); diff --git a/plugins/obs-filters/CMakeLists.txt b/plugins/obs-filters/CMakeLists.txt index 0b82720..9aa6fe9 100644 --- a/plugins/obs-filters/CMakeLists.txt +++ b/plugins/obs-filters/CMakeLists.txt @@ -20,6 +20,9 @@ if(NOT LIBRNNOISE_FOUND) "rnnoise/src/*.h" "rnnoise/include/*.h") add_definitions(-DCOMPILE_OPUS) + if("${CMAKE_SYSTEM_NAME}" MATCHES "Linux") + set_property(SOURCE ${rnnoise_SOURCES} PROPERTY COMPILE_FLAGS "-fvisibility=protected") + endif() include_directories("rnnoise/include") source_group("rnnoise" FILES ${rnnoise_SOURCES}) set(LIBRNNOISE_FOUND TRUE) diff --git a/plugins/obs-filters/data/locale/de-DE.ini b/plugins/obs-filters/data/locale/de-DE.ini index 92ec4ca..c66f3db 100644 --- a/plugins/obs-filters/data/locale/de-DE.ini +++ b/plugins/obs-filters/data/locale/de-DE.ini @@ -1,6 +1,6 @@ ColorFilter="Farbkorrektur" ColorGradeFilter="LUT anwenden" -MaskFilter="Bildmaske/‐vermischung" +MaskFilter="Bildmaske/-vermischung" AsyncDelayFilter="Videoverzögerung (asynchron)" CropFilter="Zuschneiden/Pad" ScrollFilter="Bewegung" @@ -30,11 +30,11 @@ Brightness="Helligkeit" Gamma="Gamma" BrowsePath.Images="Alle Bilddateien" BrowsePath.AllFiles="Alle Dateien" -KeyColorType="Key‐Farbtyp" -KeyColor="Key‐Farbe" +KeyColorType="Key-Farbtyp" +KeyColor="Key-Farbe" Similarity="Ähnlichkeit (1–1000)" Smoothness="Glätte (1–1000)" -ColorSpillReduction="Key‐Farbe‐Spill‐Reduzierung (1–1000)" +ColorSpillReduction="Key-Farbe-Spill-Reduzierung (1–1000)" Crop.Left="Links" Crop.Right="Rechts" Crop.Top="Oben" @@ -54,13 +54,13 @@ Blue="Blau" Magenta="Magenta" NoiseGate.OpenThreshold="Öffnungsschwellwert" NoiseGate.CloseThreshold="Schließschwellwert" -NoiseGate.AttackTime="Attack‐Zeit" -NoiseGate.HoldTime="Hold‐Zeit" -NoiseGate.ReleaseTime="Release‐Zeit" +NoiseGate.AttackTime="Attack-Zeit" +NoiseGate.HoldTime="Hold-Zeit" +NoiseGate.ReleaseTime="Release-Zeit" Gain.GainDB="Verstärkung" StretchImage="Bild strecken (Bildseitenverhältnis verwerfen)" Resolution="Auflösung" -Base.Canvas="Basis‐(Leinwand‐)Auflösung" +Base.Canvas="Basis-(Leinwand-)Auflösung" None="Keine" ScaleFiltering="Skalierungsfilterung" ScaleFiltering.Point="Point" @@ -70,7 +70,7 @@ ScaleFiltering.Lanczos="Lanczos" ScaleFiltering.Area="Area" NoiseSuppress.SuppressLevel="Unterdrückungspegel" NoiseSuppress.Method="Methode" -NoiseSuppress.Method.Speex="Speex (niedrigere CPU‐Auslastung)" +NoiseSuppress.Method.Speex="Speex (niedrigere CPU-Auslastung)" NoiseSuppress.Method.RNNoise="RNNoise (höhere Qualität)" Saturation="Sättigung" HueShift="Farbtonverschiebung" @@ -81,7 +81,7 @@ Compressor.Threshold="Schwellwert" Compressor.AttackTime="Attack" Compressor.ReleaseTime="Release" Compressor.OutputGain="Ausgabeverstärkung" -Compressor.SidechainSource="Sidechain‐/Ducking‐Quelle" +Compressor.SidechainSource="Sidechain-/Ducking-Quelle" Limiter="Limiter" Limiter.Threshold="Schwellwert" Limiter.ReleaseTime="Release" @@ -101,6 +101,6 @@ Expander.Presets.Gate="Gate" LumaKeyFilter="Luma Key" Luma.LumaMax="Max. Luma" Luma.LumaMin="Min. Luma" -Luma.LumaMaxSmooth="Max. Luma‐Glätte" -Luma.LumaMinSmooth="Min. Luma‐Glätte" +Luma.LumaMaxSmooth="Max. Luma-Glätte" +Luma.LumaMinSmooth="Min. Luma-Glätte" diff --git a/plugins/obs-filters/data/locale/el-GR.ini b/plugins/obs-filters/data/locale/el-GR.ini index b80339f..5a88e73 100644 --- a/plugins/obs-filters/data/locale/el-GR.ini +++ b/plugins/obs-filters/data/locale/el-GR.ini @@ -7,11 +7,13 @@ ScrollFilter="Κύλιση" ChromaKeyFilter="Κλειδί Chroma" ColorKeyFilter="Κλειδί Χρώματος" SharpnessFilter="Όξυνση" +Sharpness="Οξύτητα" ScaleFilter="Κλιμάκωση/αναλογίες" GPUDelayFilter="Καταστήσει καθυστέρηση" UndistortCenter="Undistort κέντρο της εικόνας κατά την κλιμάκωση από ultrawide" NoiseGate="Πύλη θορύβου" NoiseSuppress="Καταστολή θορύβου" +InvertPolarity="Αντιστροφή Φάσης" Gain="Απολαβή" DelayMs="Καθυστέρηση" Type="Τύπος" @@ -44,6 +46,7 @@ ScrollFilter.SpeedX="Οριζόντια Ταχύτητα" ScrollFilter.SpeedY="Κατακόρυφη Ταχύτητα" ScrollFilter.LimitWidth="Περιορισμός Πλάτους" ScrollFilter.LimitHeight="Περιορισμός Ύψους" +ScrollFilter.Loop="Επανάληψη" CustomColor="Προσαρμοσμένο χρώμα" Red="Κόκκινο" Green="Πράσινο" @@ -57,13 +60,18 @@ NoiseGate.ReleaseTime="Χρόνος διάχυσης" Gain.GainDB="Απολαβή" StretchImage="Τέντωση εικόνας (απόρριψη αναλογίας εικόνας)" Resolution="Ανάλυση" +Base.Canvas="Βασική Ανάλυση (Καμβάς)" None="Καμία" ScaleFiltering="Κλίμακα φιλτραρίσματος" ScaleFiltering.Point="Σημείο" ScaleFiltering.Bilinear="Διγραμμικές" ScaleFiltering.Bicubic="Δικυβική" ScaleFiltering.Lanczos="Lanczos" +ScaleFiltering.Area="Περιοχή" NoiseSuppress.SuppressLevel="Καταστολή επιπέδου" +NoiseSuppress.Method="Μέθοδος" +NoiseSuppress.Method.Speex="Speex (χαμηλότερη χρήση CPU)" +NoiseSuppress.Method.RNNoise="RNNoise (υψηλότερη ποιότητα)" Saturation="Κορεσμός" HueShift="Μετατόπιση Απόχρωσης" Amount="Ποσό" @@ -74,4 +82,25 @@ Compressor.AttackTime="Επίθεση" Compressor.ReleaseTime="Απελευθέρωση" Compressor.OutputGain="Εξόδου κέρδος" Compressor.SidechainSource="Πηγή sidechain/βουτιά" +Limiter="Περιοριστής" +Limiter.Threshold="Όριο" +Limiter.ReleaseTime="Απελευθέρωση" +Expander="Επέκταση" +Expander.Ratio="Λόγος" +Expander.Threshold="Όριο" +Expander.AttackTime="Επίθεση" +Expander.ReleaseTime="Απελευθέρωση" +Expander.OutputGain="Ένταση Εξόδου" +Expander.Detector="Ανίχνευση" +Expander.RMS="RMS" +Expander.Peak="Peak" +Expander.None="Καμία" +Expander.Presets="Προεπιλογές" +Expander.Presets.Expander="Επέκταση" +Expander.Presets.Gate="Πύλη" +LumaKeyFilter="Κλειδί Luma" +Luma.LumaMax="Μέγιστο Luma" +Luma.LumaMin="Ελάχιστο Luma" +Luma.LumaMaxSmooth="Απαλό Μέγιστο Luma" +Luma.LumaMinSmooth="Απαλό Ελάχιστο Luma" diff --git a/plugins/obs-filters/data/locale/fa-IR.ini b/plugins/obs-filters/data/locale/fa-IR.ini index db50437..bf2d25b 100644 --- a/plugins/obs-filters/data/locale/fa-IR.ini +++ b/plugins/obs-filters/data/locale/fa-IR.ini @@ -69,6 +69,9 @@ ScaleFiltering.Bicubic="دوتایی" ScaleFiltering.Lanczos="لانچوس" ScaleFiltering.Area="ناحیه" NoiseSuppress.SuppressLevel="سطح کاهش" +NoiseSuppress.Method="روش" +NoiseSuppress.Method.Speex="Speex (استفاده کمتر از پردازنده)" +NoiseSuppress.Method.RNNoise="RNNoise (کیفیت بالاتر)" Saturation="اشباع" HueShift="تغییر مکان رنگ" Amount="میزان" diff --git a/plugins/obs-filters/data/locale/fil-PH.ini b/plugins/obs-filters/data/locale/fil-PH.ini index c533d84..2d1ced2 100644 --- a/plugins/obs-filters/data/locale/fil-PH.ini +++ b/plugins/obs-filters/data/locale/fil-PH.ini @@ -65,6 +65,7 @@ ScaleFiltering.Bicubic="Bikyubik" ScaleFiltering.Lanczos="Lankzos" ScaleFiltering.Area="Laki" NoiseSuppress.SuppressLevel="Antas ng Pagpigil" +NoiseSuppress.Method="Paraan" Saturation="Pagbababad" HueShift="Kulay ng pagririlyebo" Amount="Halaga" @@ -75,7 +76,15 @@ Compressor.AttackTime="Atake" Compressor.ReleaseTime="Paglabas" Compressor.OutputGain="Makakuha ng Awput" Compressor.SidechainSource="Saydcheyn/Pinagmulan ng Daking" +Expander.Threshold="Halaga" Expander.AttackTime="Atake" Expander.ReleaseTime="Paglabas" +Expander.Detector="Pagtuklas" +Expander.RMS="RMS" +Expander.Peak="Pinakamataas" Expander.None="Wala" +Expander.Presets="Mga preset" +LumaKeyFilter="Luma na Susi" +Luma.LumaMax="Luma na Pinakamalakas" +Luma.LumaMin="Luma na Pinakamaliit" diff --git a/plugins/obs-filters/data/locale/he-IL.ini b/plugins/obs-filters/data/locale/he-IL.ini index 6186a33..3cbb6ac 100644 --- a/plugins/obs-filters/data/locale/he-IL.ini +++ b/plugins/obs-filters/data/locale/he-IL.ini @@ -41,6 +41,7 @@ ScrollFilter.SpeedX="מהירות אופקית" ScrollFilter.SpeedY="מהירות אנכית" ScrollFilter.LimitWidth="מגבלת רוחב" ScrollFilter.LimitHeight="מגבלת גובה" +ScrollFilter.Loop="לולאה" CustomColor="צבע מותאם אישית" Red="אדום" Green="ירוק" @@ -62,9 +63,11 @@ ScaleFiltering.Bicubic="ביקיוביק" ScaleFiltering.Lanczos="לנזוס" ScaleFiltering.Area="אזור" NoiseSuppress.Method="שיטה" +Amount="כמות" Compressor.ReleaseTime="שחרור" Expander.ReleaseTime="שחרור" Expander.Detector="זיהוי" Expander.None="ללא" +Expander.Presets.Gate="שער" LumaKeyFilter="מפתח Luma" diff --git a/plugins/obs-filters/data/locale/kab-KAB.ini b/plugins/obs-filters/data/locale/kab-KAB.ini new file mode 100644 index 0000000..8402fe3 --- /dev/null +++ b/plugins/obs-filters/data/locale/kab-KAB.ini @@ -0,0 +1,55 @@ +ColorFilter="Aseɣti n yini" +ScrollFilter="Adrudem" +SharpnessFilter="Semsed" +NoiseSuppress="Tukksa n usxerxec" +DelayMs="Asemmezger" +Type="Anaw" +MaskBlendType.MaskColor="Tagelmust alfa (abadu n yini)" +MaskBlendType.MaskAlpha="Tagelmust alfa (abadu alfa)" +Path="Abrid" +Color="Ini" +Opacity="Tiḍullest" +Contrast="Amyeẓli" +Brightness="Tifawit" +Gamma="Gama" +BrowsePath.Images="Akk ifuyla n tugna" +BrowsePath.AllFiles="Akk ifuyla" +KeyColorType="Anaw n yini yufraren" +KeyColor="Ini yufraren" +Crop.Left="Azelmaḍ" +Crop.Right="Ayfus" +Crop.Top="Ukessawen" +Crop.Bottom="Ukessar" +Crop.Width="Tehri" +Crop.Height="Tattayt" +Crop.Relative="Amassaɣ" +ScrollFilter.SpeedX="Arured aglawan" +ScrollFilter.SpeedY="Arured ubdid" +ScrollFilter.Loop="Tineddict" +CustomColor="Ini yugnen" +Red="Azeggaɣ" +Green="Azegzaw" +Blue="Anili" +NoiseGate.OpenThreshold="Amnaṛ n welday" +NoiseGate.CloseThreshold="Amnaṛ n wemdal" +Resolution="Tabadut" +Base.Canvas="Tabadut tazadurant (Taɣzut n usuneɣ)" +None="Ulac" +ScaleFiltering.Point="Tenqiḍin" +ScaleFiltering.Area="Taɣzut" +NoiseSuppress.SuppressLevel="Aswir n tukksa" +NoiseSuppress.Method="Tarrayt" +NoiseSuppress.Method.RNNoise="RNNoise (taɣara ifazen)" +Saturation="Tawant" +HueShift="Asekḥer n tiɣmi" +Amount="Tasmekta" +Compressor.Ratio="Assaɣ" +Compressor.ReleaseTime="Aserreḥ" +Limiter.Threshold="Amnaṛ" +Limiter.ReleaseTime="Aserreḥ" +Expander.Ratio="Assaɣ" +Expander.Threshold="Amnaṛ" +Expander.ReleaseTime="Aserreḥ" +Expander.Detector="Tifin" +Expander.None="Ulac" + diff --git a/plugins/obs-filters/data/locale/nb-NO.ini b/plugins/obs-filters/data/locale/nb-NO.ini index 90d5c83..8e3af81 100644 --- a/plugins/obs-filters/data/locale/nb-NO.ini +++ b/plugins/obs-filters/data/locale/nb-NO.ini @@ -69,6 +69,9 @@ ScaleFiltering.Bicubic="Bikubisk" ScaleFiltering.Lanczos="Lanczos" ScaleFiltering.Area="Område" NoiseSuppress.SuppressLevel="Dempelse Nivå" +NoiseSuppress.Method="Metode" +NoiseSuppress.Method.Speex="Speex (lavere CPU-Bruk)" +NoiseSuppress.Method.RNNoise="RNNoise (høyere kvalitet)" Saturation="Metning" HueShift="Fargetone Skifte" Amount="Mengde" diff --git a/plugins/obs-filters/data/locale/pt-BR.ini b/plugins/obs-filters/data/locale/pt-BR.ini index 8b40ba9..7d97edb 100644 --- a/plugins/obs-filters/data/locale/pt-BR.ini +++ b/plugins/obs-filters/data/locale/pt-BR.ini @@ -28,8 +28,8 @@ Opacity="Opacidade" Contrast="Contraste" Brightness="Brilho" Gamma="Gama" -BrowsePath.Images="Todos Arquivos de Imagem" -BrowsePath.AllFiles="Todos os Arquivos" +BrowsePath.Images="Todos os arquivos de imagem" +BrowsePath.AllFiles="Todos os arquivos" KeyColorType="Tipo de Key Color" KeyColor="Key Color" Similarity="Similaridade (1-1000)" diff --git a/plugins/obs-filters/data/locale/pt-PT.ini b/plugins/obs-filters/data/locale/pt-PT.ini index b694477..b182bcd 100644 --- a/plugins/obs-filters/data/locale/pt-PT.ini +++ b/plugins/obs-filters/data/locale/pt-PT.ini @@ -66,6 +66,7 @@ ScaleFiltering.Bicubic="Bicúbico" ScaleFiltering.Lanczos="Lanczos" ScaleFiltering.Area="Área" NoiseSuppress.SuppressLevel="Nível de Supressão" +NoiseSuppress.Method="Método" Saturation="Saturação" Amount="Montante" Compressor="Compressor" diff --git a/plugins/obs-filters/data/locale/sl-SI.ini b/plugins/obs-filters/data/locale/sl-SI.ini index d66677b..62ccc13 100644 --- a/plugins/obs-filters/data/locale/sl-SI.ini +++ b/plugins/obs-filters/data/locale/sl-SI.ini @@ -69,6 +69,9 @@ ScaleFiltering.Bicubic="Dvoprostor." ScaleFiltering.Lanczos="Lanczos" ScaleFiltering.Area="Območje" NoiseSuppress.SuppressLevel="Raven dušenja" +NoiseSuppress.Method="Metoda" +NoiseSuppress.Method.Speex="Speex (manjša poraba procesorja)" +NoiseSuppress.Method.RNNoise="RNNoise (višja kakovost)" Saturation="Nasičenost" HueShift="Zamik odtenka" Amount="Količina" diff --git a/plugins/obs-filters/rnnoise/src/denoise.c b/plugins/obs-filters/rnnoise/src/denoise.c index 53bb803..7639f74 100644 --- a/plugins/obs-filters/rnnoise/src/denoise.c +++ b/plugins/obs-filters/rnnoise/src/denoise.c @@ -172,12 +172,12 @@ static void check_init() { if (common.init) return; common.kfft = opus_fft_alloc_twiddles(2*FRAME_SIZE, NULL, NULL, NULL, 0); for (i=0;ig[i]) r[i] = 1; - else r[i] = SQUARE(Exp[i])*(1-SQUARE(g[i]))/(.001 + SQUARE(g[i])*(1-SQUARE(Exp[i]))); - r[i] = sqrt(MIN16(1, MAX16(0, r[i]))); + else r[i] = (float)(SQUARE(Exp[i])*(1-SQUARE(g[i]))/(.001 + SQUARE(g[i])*(1-SQUARE(Exp[i])))); + r[i] = (float)sqrt(MIN16(1, MAX16(0, r[i]))); #endif - r[i] *= sqrt(Ex[i]/(1e-8+Ep[i])); + r[i] *= (float)sqrt(Ex[i]/(1e-8+Ep[i])); } interp_band_gain(rf, r); for (i=0;imem_hp_x, in, b_hp, a_hp, FRAME_SIZE); silence = compute_frame_features(st, X, P, Ex, Ep, Exp, features, x); diff --git a/plugins/obs-filters/rnnoise/src/pitch.c b/plugins/obs-filters/rnnoise/src/pitch.c index fc832d1..a154918 100644 --- a/plugins/obs-filters/rnnoise/src/pitch.c +++ b/plugins/obs-filters/rnnoise/src/pitch.c @@ -419,7 +419,7 @@ static opus_val16 compute_pitch_gain(opus_val32 xy, opus_val32 xx, opus_val32 yy #else static opus_val16 compute_pitch_gain(opus_val32 xy, opus_val32 xx, opus_val32 yy) { - return xy/sqrt(1+xx*yy); + return (opus_val16)(xy/sqrt(1.0+xx*yy)); } #endif diff --git a/plugins/obs-filters/rnnoise/src/rnn.c b/plugins/obs-filters/rnnoise/src/rnn.c index d36b550..c40fd16 100644 --- a/plugins/obs-filters/rnnoise/src/rnn.c +++ b/plugins/obs-filters/rnnoise/src/rnn.c @@ -68,7 +68,7 @@ static OPUS_INLINE float tansig_approx(float x) static OPUS_INLINE float sigmoid_approx(float x) { - return .5 + .5*tansig_approx(.5*x); + return (float)(.5 + .5*tansig_approx(.5f*x)); } static OPUS_INLINE float relu(float x) diff --git a/plugins/obs-libfdk/data/locale/de-DE.ini b/plugins/obs-libfdk/data/locale/de-DE.ini index 46d00e8..87ad012 100644 --- a/plugins/obs-libfdk/data/locale/de-DE.ini +++ b/plugins/obs-libfdk/data/locale/de-DE.ini @@ -1,4 +1,4 @@ -LibFDK="libfdk‐AAC‐Encoder" +LibFDK="libfdk-AAC-Encoder" Bitrate="Bitrate" -Afterburner="AAC‐Afterburner aktivieren" +Afterburner="AAC-Afterburner aktivieren" diff --git a/plugins/obs-libfdk/data/locale/fa-IR.ini b/plugins/obs-libfdk/data/locale/fa-IR.ini index a20455a..5609d8b 100644 --- a/plugins/obs-libfdk/data/locale/fa-IR.ini +++ b/plugins/obs-libfdk/data/locale/fa-IR.ini @@ -1,4 +1,4 @@ -LibFDK="کتابخانه رمزگذار AAC" +LibFDK="libfdk رمزگذار AAC" Bitrate="نرخ بیت" Afterburner="فعال سازی رمزگذاری AAC خروجی" diff --git a/plugins/obs-libfdk/data/locale/kab-KAB.ini b/plugins/obs-libfdk/data/locale/kab-KAB.ini new file mode 100644 index 0000000..4ce29d5 --- /dev/null +++ b/plugins/obs-libfdk/data/locale/kab-KAB.ini @@ -0,0 +1,4 @@ +LibFDK="asettengal libfdk AAC" +Bitrate="Aktum" +Afterburner="Sermed AAC Afterburner" + diff --git a/plugins/obs-libfdk/data/locale/ur-PK.ini b/plugins/obs-libfdk/data/locale/ur-PK.ini index 1655d2b..602d727 100644 --- a/plugins/obs-libfdk/data/locale/ur-PK.ini +++ b/plugins/obs-libfdk/data/locale/ur-PK.ini @@ -1,4 +1,3 @@ -LibFDK="لابفدک AAC انکوڈر" Bitrate="بٹ شرح" Afterburner="بٹرا قابل اطلاق AAC بعدبورنر" diff --git a/plugins/obs-outputs/data/locale/ar-SA.ini b/plugins/obs-outputs/data/locale/ar-SA.ini index 29c197c..fd59124 100644 --- a/plugins/obs-outputs/data/locale/ar-SA.ini +++ b/plugins/obs-outputs/data/locale/ar-SA.ini @@ -5,5 +5,11 @@ FLVOutput.FilePath="مسار الملف" Default="Default" ConnectionTimedOut="انتهت مهلة الاتصال. تأكد من أن قمت بتكوين خدمة البث صالحة ولا جدار الحماية بحظر الاتصال." +PermissionDenied="تم حظر الاتصال. تحقق من جدار الحماية/إعدادات مكافحة الفيروسات للتأكد من السماح لـ OBS بالوصول الكامل للإنترنت." +ConnectionAborted="تم إحباط الاتصال. وهذا يشير عادة إلى مشاكل في الاتصال بالإنترنت بينك وبين خدمة البث." ConnectionReset="The connection was reset by the peer. This usually indicates internet connection problems between you and the streaming service." +HostNotFound="لم يتم العثور على اسم المضيف. تأكد من إدخال خادم بث صالح والاتصال بالإنترنت / DNS يعمل بشكل صحيح." +NoData="تم العثور على اسم المضيف، ولكن لا توجد بيانات من النوع المطلوب. يمكن أن يحدث هذا إذا كنت مرتبطة بعنوان IPv6 وخدمة البث الخاصة بك تحتوي فقط على عناوين IPv4 (انظر الإعدادات ← المتقدمة)." +AddressNotAvailable="العنوان غير متوفر. ربما كنت قد حاولت ربط عنوان IP غير صالح (انظر الإعدادات ← المتقدم)." +SSLCertVerifyFailed="أرسل خادم RTMP شهادة SSL غير صالحة." diff --git a/plugins/obs-outputs/data/locale/de-DE.ini b/plugins/obs-outputs/data/locale/de-DE.ini index 3602657..d2bf932 100644 --- a/plugins/obs-outputs/data/locale/de-DE.ini +++ b/plugins/obs-outputs/data/locale/de-DE.ini @@ -1,15 +1,15 @@ -RTMPStream="RTMP‐Stream" -RTMPStream.DropThreshold="Drop‐Schwellwert (Millisekunden)" -FLVOutput="FLV‐Dateiausgabe" +RTMPStream="RTMP-Stream" +RTMPStream.DropThreshold="Drop-Schwellwert (Millisekunden)" +FLVOutput="FLV-Dateiausgabe" FLVOutput.FilePath="Dateipfad" Default="Standard" -ConnectionTimedOut="Zeitüberschreitung bei der Verbindung. Stellen Sie sicher, dass Sie einen gültigen Streamingdienst konfiguriert haben und keine Firewall die Verbindung blockiert." -PermissionDenied="Die Verbindung wurde blockiert. Überprüfen Sie Ihre Firewall‐/Anti‐Virus‐Einstellungen, um sicherzustellen, dass OBS vollen Internetzugang hat." -ConnectionAborted="Die Verbindung wurde abgebrochen. Dies bedeutet in der Regel Probleme mit der Internetverbindung zwischen Ihnen und dem Streamingdienst." -ConnectionReset="Die Verbindung wurde durch den Kommunikationspartner zurückgesetzt. Dies bedeutet in der Regel Probleme mit der Internetverbindung zwischen Ihnen und dem Streamingdienst." +ConnectionTimedOut="Zeitüberschreitung bei der Verbindung. Stellen Sie sicher, dass Sie eine gültige Streamingplattform konfiguriert haben und keine Firewall die Verbindung blockiert." +PermissionDenied="Die Verbindung wurde blockiert. Überprüfen Sie Ihre Firewall-/Anti-Virus-Einstellungen, um sicherzustellen, dass OBS vollen Internetzugang hat." +ConnectionAborted="Die Verbindung wurde abgebrochen. Dies bedeutet in der Regel Probleme mit der Internetverbindung zwischen Ihnen und der Streamingplattform." +ConnectionReset="Die Verbindung wurde durch den Kommunikationspartner zurückgesetzt. Dies bedeutet in der Regel Probleme mit der Internetverbindung zwischen Ihnen und der Streamingplattform." HostNotFound="Hostname nicht gefunden. Stellen Sie sicher, dass Sie einen gültigen Streamingserver eingegeben haben und Ihr(e) Internetverbindung/DNS korrekt arbeiten." -NoData="Hostname gefunden, aber keine Daten des angeforderten Typs vorhanden. Dies kann auftreten, wenn Sie eine IPv6‐Adresse verwenden, aber Ihr Streamingdienst nur über IPv4‐Adressen verfügt. (siehe „Einstellungen“ → „Erweitert“)" -AddressNotAvailable="Adresse nicht verfügbar. Sie haben möglicherweise eine ungültige IP‐Adresse versucht zu verwenden. (siehe „Einstellungen“ → „Erweitert“)" -SSLCertVerifyFailed="Der RTMP‐Server hat ein ungültiges SSL‐Zertifikat gesendet." +NoData="Hostname gefunden, aber keine Daten des angeforderten Typs vorhanden. Dies kann auftreten, wenn Sie eine IPv6-Adresse verwenden, aber Ihre Streamingplattform nur über IPv4-Adressen verfügt. (siehe Einstellungen → Erweitert)" +AddressNotAvailable="Adresse nicht verfügbar. Sie haben möglicherweise eine ungültige IP-Adresse versucht zu verwenden. (siehe Einstellungen → Erweitert)" +SSLCertVerifyFailed="Der RTMP-Server hat ein ungültiges SSL-Zertifikat gesendet." diff --git a/plugins/obs-outputs/data/locale/el-GR.ini b/plugins/obs-outputs/data/locale/el-GR.ini index 621bd41..160509a 100644 --- a/plugins/obs-outputs/data/locale/el-GR.ini +++ b/plugins/obs-outputs/data/locale/el-GR.ini @@ -9,4 +9,7 @@ PermissionDenied="Αποκλείστηκε η σύνδεση. Ελέγξτε τ ConnectionAborted="Η σύνδεση ματαιώθηκε. Αυτό συνήθως υποδεικνύει προβλήματα σύνδεσης στο διαδίκτυο ανάμεσα σε εσάς και την υπηρεσία συνεχούς ροής." ConnectionReset="Η σύνδεση ήταν επαναφέρθηκε στον ομότιμο υπολογιστή. Αυτό συνήθως υποδεικνύει προβλήματα σύνδεσης στο διαδίκτυο ανάμεσα σε εσάς και την υπηρεσία συνεχούς ροής." HostNotFound="Το όνομα του κεντρικού υπολογιστή δεν βρέθηκε. Βεβαιωθείτε ότι πληκτρολογήσατε έναν έγκυρο διακομιστή συνεχούς ροής και η σύνδεση στο διαδίκτυο / DNS λειτουργεί σωστά." +NoData="Το όνομα του κεντρικού υπολογιστή βρέθηκε, αλλά χωρίς δεδομένα του ζητούμενου τύπου. Αυτό μπορεί να συμβεί αν έχετε δεσμεύσει μια διεύθυνση IPv6 και για η υπηρεσία συνεχούς ροής διαθέτει μόνο διευθύνσεις IPv4 (ανατρέξτε στην ενότητα Ρυθμίσεις → Για Προχωρημένους)." +AddressNotAvailable="Η διεύθυνση δεν είναι διαθέσιμη. Μπορεί να Δοκιμάσατε να συνδεθείτε σε μια άκυρη διεύθυνση IP (ανατρέξτε στην ενότητα Ρυθμίσεις → Για Προχωρημένους)." +SSLCertVerifyFailed="Ο διακομιστής RTMP έστειλε ένα άκυρο πιστοποιητικό SSL." diff --git a/plugins/obs-outputs/data/locale/kab-KAB.ini b/plugins/obs-outputs/data/locale/kab-KAB.ini new file mode 100644 index 0000000..bf236d9 --- /dev/null +++ b/plugins/obs-outputs/data/locale/kab-KAB.ini @@ -0,0 +1,14 @@ +RTMPStream="Asuddem n RTMP" +FLVOutput="Tuffɣa ɣer ufaylu FLV" +FLVOutput.FilePath="Abrid n ufaylu" +Default="Amezwar" + +ConnectionTimedOut="Tuqqna tfut. Tḥeq belli tesɣewreḍ ameẓlu n usuddem ameɣtu yerna ulac aɣrab b tmes i yesswaḥlen tuqqna." +PermissionDenied="Tuqqna tettusewḥel. Selken iɣewwaren n uɣrab n tmes neɣ nuseɣẓan mgalavirus akken ad tetḥeqqeḍ belli OBS yesɛa adduf ummid ɣer internet." +ConnectionAborted="Tuqqna tegzem. Ayagi immal di tegti ugur n tuqqna ɣer internet gar-ak m akked umeẓlu n usuddem." +ConnectionReset="Tuqqna tules awennez. Ayagi immal di tegti ugur n tuqqna ɣer internet gar-ak m akked umeẓlu n usuddem." +HostNotFound="Isem n usneftaɣ ur yettwaf ara. Tḥeq belli tsekcmeḍ aqeddac ameɣtu n usuddem yerna tuqqna-inek ɣer internet / DNS tteddun akken iwata." +NoData="Isem n usneftaɣ yettwaf, maca ulac isefka n wanaw i tsutreḍ. Ayagi yezmer ad d-iḍru ma tesqedceḍ tansa IPv6 yerna ameẓlu n usuddem yesɛa kan tansiwin IPv4 (ẓer Iɣewwaren → Anaẓi)." +AddressNotAvailable="Tansa ur tewjid ara. Ahat tɛerḍeḍ ad tt-tarzeḍ ɣer tansa IP tarmeɣtut (ẓer Iɣewwaren→ Anaẓi)." +SSLCertVerifyFailed="Aqeddac RTMP yuzen-d aselkin SSL armeɣtu." + diff --git a/plugins/obs-outputs/data/locale/ro-RO.ini b/plugins/obs-outputs/data/locale/ro-RO.ini index 0f352a3..f58889e 100644 --- a/plugins/obs-outputs/data/locale/ro-RO.ini +++ b/plugins/obs-outputs/data/locale/ro-RO.ini @@ -6,10 +6,10 @@ Default="Implicit" ConnectionTimedOut="Conexiunea a expirat. Asigură-te că ai configurat un serviciu de streaming valid și că nici un firewall nu blochează conexiunea." PermissionDenied="Conexiunea a fost blocată. Verificați setările firewall-ului / anti-virus pentru a vă asigura că OBS are acces complet la internet." -ConnectionAborted="Conexiunea a fost întreruptă. Acest lucru indică de obicei probleme de conexiune la internet între dvs. și serviciul de streaming." -ConnectionReset="Conexiunea a fost întreruptă. Acest lucru indică de obicei probleme de conexiune la internet între dvs. și serviciul de streaming." +ConnectionAborted="Conexiunea a fost întreruptă. Acest lucru indică de obicei probleme de conexiune la internet între tine și serviciul de transmisiune." +ConnectionReset="Conexiunea a fost resetată de partener. Acest lucru indică de obicei probleme de conexiune la internet între tine și serviciul de transmisiune." HostNotFound="Hostname nu a fost găsit. Asigură-te că ai introdus un server valid de streaming și că conexiunea la internet/DNS funcționează corect." -NoData="A fost găsit numele gazdei, dar nu există date de tipul solicitat. Acest lucru poate apărea dacă aveți o adresă IPv6 și serviciul dvs. de streaming are doar adrese IPv4 (vezi Setări → Avansat)." +NoData="A fost găsit numele gazdei, dar nu există date de tipul solicitat. Acest lucru se poate întâmpla dacă ai o adresă IPv6 și serviciul de transmisiune are doar adrese IPv4 (vezi Setări → Avansate)." AddressNotAvailable="Adresa nu este disponibilă. Este posibil să fi încercat conectarea la o adresă IP invalidă (vezi Setări → Avansat)." SSLCertVerifyFailed="Serverul RTMP a trimis un certificat SSL nevalid." diff --git a/plugins/obs-outputs/librtmp/rtmp.c b/plugins/obs-outputs/librtmp/rtmp.c index 2252766..a803202 100644 --- a/plugins/obs-outputs/librtmp/rtmp.c +++ b/plugins/obs-outputs/librtmp/rtmp.c @@ -348,6 +348,12 @@ RTMP_TLS_LoadCerts(RTMP *r) { "/etc/ssl/certs"); goto error; } +#elif defined(__OpenBSD__) + if (mbedtls_x509_crt_parse_file(chain, "/etc/ssl/cert.pem") < 0) { + RTMP_Log(RTMP_LOGERROR, "mbedtls_x509_crt_parse_file: Couldn't parse " + "/etc/ssl/cert.pem"); + goto error; + } #endif mbedtls_ssl_conf_ca_chain(&r->RTMP_TLS_ctx->conf, chain, NULL); @@ -814,8 +820,10 @@ add_addr_info(struct sockaddr_storage *service, socklen_t *addrlen, AVal *host, *socket_error = WSANO_DATA; #elif __FreeBSD__ *socket_error = ENOATTR; -#else +#elif defined(ENODATA) *socket_error = ENODATA; +#else + *socket_error = EAFNOSUPPORT; #endif RTMP_Log(RTMP_LOGERROR, "Could not resolve server '%s': no valid address found", hostname); @@ -3382,10 +3390,9 @@ HandleInvoke(RTMP *r, const char *body, unsigned int nBodySize) else { + RTMP_Log(RTMP_LOGWARNING, "Unhandled: %s:\n%s", r->Link.tcUrl.av_val, code.av_val); if (description.av_len) - RTMP_Log(RTMP_LOGWARNING, "Unhandled: %s:\n%s (%s)", r->Link.tcUrl.av_val, code.av_val, description.av_val); - else - RTMP_Log(RTMP_LOGWARNING, "Unhandled: %s:\n%s", r->Link.tcUrl.av_val, code.av_val); + RTMP_Log(RTMP_LOGDEBUG, "Description: %s", description.av_val); } } else if (AVMATCH(&method, &av_playlist_ready)) diff --git a/plugins/obs-text/data/locale/de-DE.ini b/plugins/obs-text/data/locale/de-DE.ini index 8f2b137..f53f84f 100644 --- a/plugins/obs-text/data/locale/de-DE.ini +++ b/plugins/obs-text/data/locale/de-DE.ini @@ -2,7 +2,7 @@ TextGDIPlus="Text (GDI+)" Font="Schriftart" Text="Text" ReadFromFile="Aus Datei lesen" -TextFile="Textdatei (UTF‐8)" +TextFile="Textdatei (UTF-8)" Filter.TextFiles="Textdateien" Filter.AllFiles="Alle Dateien" Color="Farbe" diff --git a/plugins/obs-text/data/locale/el-GR.ini b/plugins/obs-text/data/locale/el-GR.ini index 0b070f7..898c5a3 100644 --- a/plugins/obs-text/data/locale/el-GR.ini +++ b/plugins/obs-text/data/locale/el-GR.ini @@ -31,4 +31,10 @@ UseCustomExtents="Χρήση Προσαρμοσμένων Επεκτάσεων UseCustomExtents.Wrap="Αναδίπλωση" Width="Πλάτος" Height="Ύψος" +Transform="Μετασχηματισμός Κειμένου" +Transform.None="Κανένας" +Transform.Uppercase="Κεφαλαία" +Transform.Lowercase="Πεζά" +Transform.Startcase="Το πρώτο γράμμα Κεφαλαίο" +Antialiasing="Ενεργοποίηση Εξομάλυνσης" diff --git a/plugins/obs-text/data/locale/et-EE.ini b/plugins/obs-text/data/locale/et-EE.ini index d8cebd3..d27cd9b 100644 --- a/plugins/obs-text/data/locale/et-EE.ini +++ b/plugins/obs-text/data/locale/et-EE.ini @@ -7,6 +7,7 @@ Filter.TextFiles="Tekstifailid" Filter.AllFiles="Kõik failid" Color="Värv" Opacity="Läbipaistvus" +Gradient="Gradient" BkOpacity="Tausta läbipaistvus" Alignment="Joondus" Alignment.Left="Vasakule" @@ -20,6 +21,10 @@ Outline="Kontuur" Outline.Size="Kontuuri suurus" Outline.Color="Kontuuri värv" Outline.Opacity="Kontuuri läbipaistvus" +UseCustomExtents.Wrap="Ümbris" Width="Laius" Height="Kõrgus" +Transform.None="Puudub" +Transform.Uppercase="Suurtähed" +Transform.Lowercase="Väiketähed" diff --git a/plugins/obs-text/data/locale/fa-IR.ini b/plugins/obs-text/data/locale/fa-IR.ini index b7d7218..9fedbec 100644 --- a/plugins/obs-text/data/locale/fa-IR.ini +++ b/plugins/obs-text/data/locale/fa-IR.ini @@ -35,4 +35,6 @@ Transform="تبدیل متن" Transform.None="هیچ‌کدام" Transform.Uppercase="حروف بزرگ" Transform.Lowercase="حروف کوچک" +Transform.Startcase="شروع مورد" +Antialiasing="فعال کردن ضد لبه" diff --git a/plugins/obs-text/data/locale/he-IL.ini b/plugins/obs-text/data/locale/he-IL.ini index c96394e..ca16ed2 100644 --- a/plugins/obs-text/data/locale/he-IL.ini +++ b/plugins/obs-text/data/locale/he-IL.ini @@ -17,16 +17,24 @@ 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="גובה" Transform="אותיות גדולות/קטנות" Transform.None="ללא" Transform.Uppercase="אותיות גדולות" Transform.Lowercase="אותיות קטנות" +Transform.Startcase="אות גדולה ראשונה בכל מילה" +Antialiasing="הפעל החלקת קצוות" diff --git a/plugins/obs-text/data/locale/kab-KAB.ini b/plugins/obs-text/data/locale/kab-KAB.ini new file mode 100644 index 0000000..d69f714 --- /dev/null +++ b/plugins/obs-text/data/locale/kab-KAB.ini @@ -0,0 +1,34 @@ +TextGDIPlus="Aḍris (GDI+)" +Font="Tasefsit" +Text="Aḍris" +ReadFromFile="Ɣer-d seg ufaylu" +TextFile="Afaylu aḍris (UTF-8)" +Filter.TextFiles="Ifuyla iḍrisen" +Filter.AllFiles="Akk ifuyla" +Color="Ini" +Opacity="Tiḍullest" +Gradient="Afesnaw" +Gradient.Color="Ini n ufesnaw" +Gradient.Opacity="Tiḍullest n ufesnaw" +Gradient.Direction="Tanila n ufesnaw" +BkColor="Ini n ugilal" +BkOpacity="Tiḍullest n ugilal" +Alignment.Left="Azelmaḍ" +Alignment.Center="Alemmas" +Alignment.Right="Ayfus" +Vertical="Ubdid" +VerticalAlignment.Top="Ukessawen" +VerticalAlignment.Bottom="Ukessar" +Outline="Azizdew" +Outline.Size="Tiddi n uzizdew" +Outline.Color="Ini n uzizdew" +Outline.Opacity="Tiḍullet n uzizdew" +ChatlogMode="Askar n umeslay" +Width="Tehri" +Height="Tattayt" +Transform="Aselket n uḍris" +Transform.None="Ulac" +Transform.Uppercase="Asekkil ameqran" +Transform.Lowercase="Asekkil ameẓyan" +Antialiasing="Sermed amzay" + diff --git a/plugins/obs-text/data/locale/nb-NO.ini b/plugins/obs-text/data/locale/nb-NO.ini index 8853c98..aaf2233 100644 --- a/plugins/obs-text/data/locale/nb-NO.ini +++ b/plugins/obs-text/data/locale/nb-NO.ini @@ -36,4 +36,5 @@ Transform.None="Ingen" Transform.Uppercase="Store bokstaver" Transform.Lowercase="Små bokstaver" Transform.Startcase="Stor forbokstav i alle ord" +Antialiasing="Aktiver antialiasing" diff --git a/plugins/obs-text/data/locale/pt-BR.ini b/plugins/obs-text/data/locale/pt-BR.ini index a35ee68..8842691 100644 --- a/plugins/obs-text/data/locale/pt-BR.ini +++ b/plugins/obs-text/data/locale/pt-BR.ini @@ -1,40 +1,40 @@ TextGDIPlus="Texto (GDI+)" Font="Fonte" Text="Texto" -ReadFromFile="Carregar do Arquivo" -TextFile="Arquivo de Texto (UTF-8)" -Filter.TextFiles="Arquivos de Texto" -Filter.AllFiles="Todos os Arquivos" +ReadFromFile="Carregar do arquivo" +TextFile="Arquivo de texto (UTF-8)" +Filter.TextFiles="Arquivos de texto" +Filter.AllFiles="Todos os arquivos" Color="Cor" Opacity="Opacidade" Gradient="Gradiente" -Gradient.Color="Cor do Gradiente" -Gradient.Opacity="Opacidade do Gradiente" -Gradient.Direction="Direção do Gradiente" -BkColor="Cor de Fundo" -BkOpacity="Opacidade de Fundo" +Gradient.Color="Cor do gradiente" +Gradient.Opacity="Opacidade do gradiente" +Gradient.Direction="Direção do gradiente" +BkColor="Cor do fundo" +BkOpacity="Opacidade do fundo" Alignment="Alinhamento" Alignment.Left="Esquerda" Alignment.Center="Centralizado" Alignment.Right="Direita" Vertical="Vertical" -VerticalAlignment="Alinhamento Vertical" +VerticalAlignment="Alinhamento vertical" VerticalAlignment.Top="Em cima" VerticalAlignment.Bottom="Em baixo" Outline="Contorno" -Outline.Size="Tamanho do Contorno" -Outline.Color="Cor do Contorno" -Outline.Opacity="Opacidade do Contorno" -ChatlogMode="Modo de Chat" -ChatlogMode.Lines="Limite de Linhas do Chat" +Outline.Size="Tamanho do contorno" +Outline.Color="Cor do contorno" +Outline.Opacity="Opacidade do contorno" +ChatlogMode="Modo de chat" +ChatlogMode.Lines="Limite de linhas do chat" UseCustomExtents="Usar extensões de texto personalizadas" UseCustomExtents.Wrap="Ajustar" Width="Largura" Height="Altura" Transform="Transformação" Transform.None="Nenhuma" -Transform.Uppercase="Letras Maiúsculas" -Transform.Lowercase="Letras Minúsculas" -Transform.Startcase="Capitular" -Antialiasing="Ativar Anti-Aliasing" +Transform.Uppercase="Letras maiúsculas" +Transform.Lowercase="Letras minúsculas" +Transform.Startcase="Capitalizar" +Antialiasing="Ativar anti-aliasing" diff --git a/plugins/obs-text/data/locale/ro-RO.ini b/plugins/obs-text/data/locale/ro-RO.ini index 0efd826..9ea45b5 100644 --- a/plugins/obs-text/data/locale/ro-RO.ini +++ b/plugins/obs-text/data/locale/ro-RO.ini @@ -7,10 +7,10 @@ Filter.TextFiles="Fișiere text" Filter.AllFiles="Toate fișierele" Color="Culoare" Opacity="Opacitate" -Gradient="Degradeu" -Gradient.Color="Culoare Gradient" -Gradient.Opacity="Opacitate Gradient" -Gradient.Direction="Direcție Gradient" +Gradient="Gradient" +Gradient.Color="Culoarea gradientului" +Gradient.Opacity="Opacitatea gradientului" +Gradient.Direction="Direcția gradientului" BkColor="Culoarea fundalului" BkOpacity="Opacitatea fundalului" Alignment="Aliniere" @@ -25,15 +25,16 @@ Outline="Contur" Outline.Size="Dimensiunea conturului" Outline.Color="Culoarea conturului" Outline.Opacity="Opacitatea conturului" -ChatlogMode="Mod Chatlog" -ChatlogMode.Lines="Limită linie chatlog" -UseCustomExtents="Utilizaţi extensii personalizate ale textului" -UseCustomExtents.Wrap="Infașoară" +ChatlogMode="Mod pentru jurnal de chat" +ChatlogMode.Lines="Limită pentru liniile jurnalului de chat" +UseCustomExtents="Folosește extinderi personalizate ale textului" +UseCustomExtents.Wrap="Încadrează textul" Width="Lățime" Height="Înălțime" -Transform="Transformare text" +Transform="Transformare de text" Transform.None="Niciuna" -Transform.Uppercase="Majuscule" +Transform.Uppercase="Litere mari" Transform.Lowercase="Litere mici" -Transform.Startcase="Pornire Caz" +Transform.Startcase="Majuscule numai la prima literă a fiecărui cuvânt" +Antialiasing="Activează antialiasingul" diff --git a/plugins/obs-transitions/data/locale/ar-SA.ini b/plugins/obs-transitions/data/locale/ar-SA.ini index d6255ac..047318b 100644 --- a/plugins/obs-transitions/data/locale/ar-SA.ini +++ b/plugins/obs-transitions/data/locale/ar-SA.ini @@ -1,5 +1,7 @@ FadeTransition="تلاشي" CutTransition="قطع" +SwipeTransition="تمرير" +SlideTransition="انزلاق" FadeToColorTransition="تلاشي إلى لون" Direction="الإتجاه" Direction.Left="يسار" @@ -7,4 +9,17 @@ Direction.Right="يمين" Direction.Up="أعلى" Direction.Down="أسفل" Color="اللون" - +TransitionPointTypeFrame="الإطار" +TransitionPointTypeTime="الوقت (بالمللي ثانية)" +AudioFadeStyle="نمط تلاشي الصوت" +LumaWipe.Image="الصورة" +LumaWipe.Invert="عكس" +LumaWipe.Type.BoxBottomLeft="الصندوق بالوسط يسار" +LumaWipe.Type.BoxBottomRight="الصندوق بالوسط يمين" +LumaWipe.Type.BoxTopLeft="الصندوق بالاعلى يسار" +LumaWipe.Type.BoxTopRight="الصندوق بالاعلى يمين" +LumaWipe.Type.Circles="الدوائر" +LumaWipe.Type.Clock="الساعة" +LumaWipe.Type.Cloud="سحابة" +LumaWipe.Type.Curtain="ستار" +HardwareDecode="استخدم فك تشفير الأجهزة عند توفرها" diff --git a/plugins/obs-transitions/data/locale/ba-RU.ini b/plugins/obs-transitions/data/locale/ba-RU.ini index b51b967..8636c9d 100644 --- a/plugins/obs-transitions/data/locale/ba-RU.ini +++ b/plugins/obs-transitions/data/locale/ba-RU.ini @@ -6,4 +6,3 @@ TransitionPointTypeFrame="Кадр" LumaWipe.Image="Һүрәт" LumaWipe.Type.Clock="Сәғәт" LumaWipe.Type.Cloud="Болот" - diff --git a/plugins/obs-transitions/data/locale/bg-BG.ini b/plugins/obs-transitions/data/locale/bg-BG.ini index c822503..8e75836 100644 --- a/plugins/obs-transitions/data/locale/bg-BG.ini +++ b/plugins/obs-transitions/data/locale/bg-BG.ini @@ -27,4 +27,3 @@ LumaWipe.Type.Stripes="Ивици" LumaWipe.Type.Watercolor="Воден цвят" LumaWipe.Type.ZigzagHorizontal="Водоравен зигзаг" LumaWipe.Type.ZigzagVertical="Отвесен зигзаг" - diff --git a/plugins/obs-transitions/data/locale/bn-BD.ini b/plugins/obs-transitions/data/locale/bn-BD.ini index 2b5c609..60b0e44 100644 --- a/plugins/obs-transitions/data/locale/bn-BD.ini +++ b/plugins/obs-transitions/data/locale/bn-BD.ini @@ -8,4 +8,3 @@ LumaWipeTransition="লুমা আল নামি মুছে ফেলু LumaWipe.Image="ছবি" LumaWipe.Invert="বিপরীতমুখী" LumaWipe.Softness="তারল্য" - diff --git a/plugins/obs-transitions/data/locale/ca-ES.ini b/plugins/obs-transitions/data/locale/ca-ES.ini index 4d885e1..636401a 100644 --- a/plugins/obs-transitions/data/locale/ca-ES.ini +++ b/plugins/obs-transitions/data/locale/ca-ES.ini @@ -63,4 +63,4 @@ AudioMonitoring="Monitorització d'àudio" AudioMonitoring.None="Monitorització desactivada" AudioMonitoring.MonitorOnly="Només monitorització (sortida silenciosa)" AudioMonitoring.Both="Monitorització i sortida" - +HardwareDecode="Usa la descodificació per maquinari si és disponible" diff --git a/plugins/obs-transitions/data/locale/cs-CZ.ini b/plugins/obs-transitions/data/locale/cs-CZ.ini index 651046d..9338586 100644 --- a/plugins/obs-transitions/data/locale/cs-CZ.ini +++ b/plugins/obs-transitions/data/locale/cs-CZ.ini @@ -63,4 +63,4 @@ AudioMonitoring="Sledování zvuku" AudioMonitoring.None="Sledování vypnuto" AudioMonitoring.MonitorOnly="Pouze sledovat (ztlumit výstup)" AudioMonitoring.Both="Sledovat i odesílat na výstup" - +HardwareDecode="Použít hardwarové dekódování, pokud je k dispozici" diff --git a/plugins/obs-transitions/data/locale/da-DK.ini b/plugins/obs-transitions/data/locale/da-DK.ini index 8f11d53..477cfa8 100644 --- a/plugins/obs-transitions/data/locale/da-DK.ini +++ b/plugins/obs-transitions/data/locale/da-DK.ini @@ -63,4 +63,4 @@ AudioMonitoring="Lydmonitering" AudioMonitoring.None="Monitering Fra" AudioMonitoring.MonitorOnly="Kun monitering (forstum output)" AudioMonitoring.Both="Monitorering og output" - +HardwareDecode="Benyt hardwareafkodning, når tilgængelig" diff --git a/plugins/obs-transitions/data/locale/de-DE.ini b/plugins/obs-transitions/data/locale/de-DE.ini index 53b9816..728e83d 100644 --- a/plugins/obs-transitions/data/locale/de-DE.ini +++ b/plugins/obs-transitions/data/locale/de-DE.ini @@ -18,7 +18,7 @@ TransitionPointType="Übergangspunkttyp" TransitionPointTypeFrame="Frame" TransitionPointTypeTime="Zeit (Millisekunden)" AudioFadeStyle="Audioübergangsstil" -AudioFadeStyle.FadeOutFadeIn="Zu Übergangspunkt aus‐ und dann einblenden" +AudioFadeStyle.FadeOutFadeIn="Zu Übergangspunkt aus- und dann einblenden" AudioFadeStyle.CrossFade="Überblendung" SwitchPoint="Farbhöhepunkt" LumaWipeTransition="Luma Wipe" @@ -47,8 +47,8 @@ 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.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" @@ -57,10 +57,10 @@ LumaWipe.Type.Stripes="Streifen" LumaWipe.Type.StripsHorizontal="Horizontale Streifen" LumaWipe.Type.StripsVertical="Vertikale Streifen" LumaWipe.Type.Watercolor="Aquarell" -LumaWipe.Type.ZigzagHorizontal="Zick‐Zack horizontal" -LumaWipe.Type.ZigzagVertical="Zick‐Zack vertikal" -AudioMonitoring="Audio‐Monitoring" +LumaWipe.Type.ZigzagHorizontal="Zick-Zack horizontal" +LumaWipe.Type.ZigzagVertical="Zick-Zack vertikal" +AudioMonitoring="Audio-Monitoring" AudioMonitoring.None="Monitor aus" AudioMonitoring.MonitorOnly="Nur Monitor (Ausgabe stummschalten)" AudioMonitoring.Both="Monitor und Ausgabe" - +HardwareDecode="Hardwaredecodierung verwenden, falls verfügbar" diff --git a/plugins/obs-transitions/data/locale/el-GR.ini b/plugins/obs-transitions/data/locale/el-GR.ini index 6429272..5cd3f7c 100644 --- a/plugins/obs-transitions/data/locale/el-GR.ini +++ b/plugins/obs-transitions/data/locale/el-GR.ini @@ -12,6 +12,7 @@ Direction.Down="Κάτω" SwipeIn="Σύρετε προς τα επάνω" Color="Χρώμα" VideoFile="Αρχείο Βίντεο" +TransitionPoint="Σημείο Μετάβασης" TransitionPointFrame="Σημείο μετάβασης (πλαίσιο)" TransitionPointType="Τύπος σημείου μετάβασης" TransitionPointTypeFrame="Καρέ" @@ -19,6 +20,7 @@ TransitionPointTypeTime="Χρόνος (χιλιοστά δευτερολέπτο AudioFadeStyle="Στυλ ήχου Fade" AudioFadeStyle.FadeOutFadeIn="Fade out στο σημείο μετάβασης στη συνέχεια, fade in" AudioFadeStyle.CrossFade="Σταδιακή Εξασθένιση" +SwitchPoint="Κορυφή Χρώματος" LumaWipeTransition="Luma Wipe" LumaWipe.Image="Εικόνα" LumaWipe.Invert="Αντιστροφή" @@ -61,4 +63,4 @@ AudioMonitoring="Ηχητική παρακολούθηση" AudioMonitoring.None="Monitor Off" AudioMonitoring.MonitorOnly="Μόνο η οθόνη (σίγαση εξόδου)" AudioMonitoring.Both="Παρακολούθηση και έξοδος" - +HardwareDecode="Χρήση αποκωδικοποίησης υλικού όταν είναι διαθέσιμη" diff --git a/plugins/obs-transitions/data/locale/en-GB.ini b/plugins/obs-transitions/data/locale/en-GB.ini index 5023ad7..864e82b 100644 --- a/plugins/obs-transitions/data/locale/en-GB.ini +++ b/plugins/obs-transitions/data/locale/en-GB.ini @@ -63,4 +63,4 @@ AudioMonitoring="Audio Monitoring" AudioMonitoring.None="Monitor Off" AudioMonitoring.MonitorOnly="Monitor Only (mute output)" AudioMonitoring.Both="Monitor and Output" - +HardwareDecode="Use hardware decoding when available" diff --git a/plugins/obs-transitions/data/locale/en-US.ini b/plugins/obs-transitions/data/locale/en-US.ini index 0a7141f..c3f58bc 100644 --- a/plugins/obs-transitions/data/locale/en-US.ini +++ b/plugins/obs-transitions/data/locale/en-US.ini @@ -63,3 +63,4 @@ AudioMonitoring="Audio Monitoring" AudioMonitoring.None="Monitor Off" AudioMonitoring.MonitorOnly="Monitor Only (mute output)" AudioMonitoring.Both="Monitor and Output" +HardwareDecode="Use hardware decoding when available" \ No newline at end of file diff --git a/plugins/obs-transitions/data/locale/es-ES.ini b/plugins/obs-transitions/data/locale/es-ES.ini index 03f27e6..242d899 100644 --- a/plugins/obs-transitions/data/locale/es-ES.ini +++ b/plugins/obs-transitions/data/locale/es-ES.ini @@ -63,4 +63,4 @@ AudioMonitoring="Monitoreo de audio" AudioMonitoring.None="Monitoreo apagado" AudioMonitoring.MonitorOnly="Solo monitoreo (salida silenciosa)" AudioMonitoring.Both="Monitoreo y salida" - +HardwareDecode="Usar decodificación por hardware cuando esté disponible" diff --git a/plugins/obs-transitions/data/locale/et-EE.ini b/plugins/obs-transitions/data/locale/et-EE.ini index 7c61114..1913d70 100644 --- a/plugins/obs-transitions/data/locale/et-EE.ini +++ b/plugins/obs-transitions/data/locale/et-EE.ini @@ -26,4 +26,3 @@ LumaWipe.Type.Squares="Ruudud" LumaWipe.Type.Stripes="Triibud" LumaWipe.Type.StripsHorizontal="Horisontaalsed triibud" LumaWipe.Type.StripsVertical="Vertikaalsed triibud" - diff --git a/plugins/obs-transitions/data/locale/eu-ES.ini b/plugins/obs-transitions/data/locale/eu-ES.ini index a7fee43..dcbfa36 100644 --- a/plugins/obs-transitions/data/locale/eu-ES.ini +++ b/plugins/obs-transitions/data/locale/eu-ES.ini @@ -63,4 +63,3 @@ AudioMonitoring="Adioaren monitorizazioa" AudioMonitoring.None="Ez monitorizatu" AudioMonitoring.MonitorOnly="Monitorea bakarrik (irteera mututua)" AudioMonitoring.Both="Monitorea eta irteera" - diff --git a/plugins/obs-transitions/data/locale/fa-IR.ini b/plugins/obs-transitions/data/locale/fa-IR.ini new file mode 100644 index 0000000..424375d --- /dev/null +++ b/plugins/obs-transitions/data/locale/fa-IR.ini @@ -0,0 +1,66 @@ +FadeTransition="محو شدن" +CutTransition="برش" +SwipeTransition="کشیدن" +SlideTransition="اسلاید" +StingerTransition="استینگر" +FadeToColorTransition="محو شدن به رنگ" +Direction="جهت" +Direction.Left="چپ" +Direction.Right="راست" +Direction.Up="بالا" +Direction.Down="پایین" +SwipeIn="کشیدن داخل" +Color="رنگ" +VideoFile="فایل ویدئو" +TransitionPoint="نقطه انتقال" +TransitionPointFrame="نقطه انتقال (قاب)" +TransitionPointType="نوع نقطه انتقال" +TransitionPointTypeFrame="قاب" +TransitionPointTypeTime="زمان (میلی ثانیه)" +AudioFadeStyle="سبک محو صدا" +AudioFadeStyle.FadeOutFadeIn="محو شدن در نقطه انتقال و سپس ظاهر شدن" +AudioFadeStyle.CrossFade="ضربدری" +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="زیگ زاگ عمودی" +AudioMonitoring="نظارت صوتی" +AudioMonitoring.None="نمایش خاموش" +AudioMonitoring.MonitorOnly="فقط نمایش (خروجی بیصدا)" +AudioMonitoring.Both="نمایش و خروجی" +HardwareDecode="در صورت وجود از رمزگشایی سخت افزاری استفاده کنید" diff --git a/plugins/obs-transitions/data/locale/fi-FI.ini b/plugins/obs-transitions/data/locale/fi-FI.ini index 75b722b..e6b647a 100644 --- a/plugins/obs-transitions/data/locale/fi-FI.ini +++ b/plugins/obs-transitions/data/locale/fi-FI.ini @@ -63,4 +63,4 @@ AudioMonitoring="Äänen monitorointi" AudioMonitoring.None="Monitorointi pois" AudioMonitoring.MonitorOnly="Vain monitorointi (hiljennä ulostulo)" AudioMonitoring.Both="Monitorointi ja ulostulo" - +HardwareDecode="Käytä laitteistotason purkua, kun mahdollista" diff --git a/plugins/obs-transitions/data/locale/fil-PH.ini b/plugins/obs-transitions/data/locale/fil-PH.ini index 6b7122e..3f2acb9 100644 --- a/plugins/obs-transitions/data/locale/fil-PH.ini +++ b/plugins/obs-transitions/data/locale/fil-PH.ini @@ -61,4 +61,3 @@ AudioMonitoring="Pagsubaybay sa Audio" AudioMonitoring.None="I-off ang Pagsubaybay" AudioMonitoring.MonitorOnly="Magsubaybay lang (i-mute ang output)" AudioMonitoring.Both="Subaybayan at Output" - diff --git a/plugins/obs-transitions/data/locale/fr-FR.ini b/plugins/obs-transitions/data/locale/fr-FR.ini index 4847606..2665498 100644 --- a/plugins/obs-transitions/data/locale/fr-FR.ini +++ b/plugins/obs-transitions/data/locale/fr-FR.ini @@ -63,4 +63,4 @@ AudioMonitoring="Monitoring audio" AudioMonitoring.None="Pas de Monitoring" AudioMonitoring.MonitorOnly="Monitoring seul (sortie coupée)" AudioMonitoring.Both="Monotoring et sortie" - +HardwareDecode="Utiliser le décodage matériel (si disponible)" diff --git a/plugins/obs-transitions/data/locale/gd-GB.ini b/plugins/obs-transitions/data/locale/gd-GB.ini index 531b1c3..3c9c5c2 100644 --- a/plugins/obs-transitions/data/locale/gd-GB.ini +++ b/plugins/obs-transitions/data/locale/gd-GB.ini @@ -23,4 +23,3 @@ AudioMonitoring="Sgrùdadh fuaime" AudioMonitoring.None="Gun sgrùdadh" AudioMonitoring.MonitorOnly="Sgrùdadh a-mhàin (mùch an t-às-chur)" AudioMonitoring.Both="Sgrùdadh is às-chur" - diff --git a/plugins/obs-transitions/data/locale/gl-ES.ini b/plugins/obs-transitions/data/locale/gl-ES.ini index df793e3..a95568f 100644 --- a/plugins/obs-transitions/data/locale/gl-ES.ini +++ b/plugins/obs-transitions/data/locale/gl-ES.ini @@ -63,4 +63,4 @@ AudioMonitoring="Monitorización do son" AudioMonitoring.None="Monitor apagado" AudioMonitoring.MonitorOnly="Só o monitor (silenciar a saída)" AudioMonitoring.Both="Monitor e saída" - +HardwareDecode="Usar a descodificación por hardware cando estea dispoñíbel" diff --git a/plugins/obs-transitions/data/locale/he-IL.ini b/plugins/obs-transitions/data/locale/he-IL.ini index e2929fa..2731839 100644 --- a/plugins/obs-transitions/data/locale/he-IL.ini +++ b/plugins/obs-transitions/data/locale/he-IL.ini @@ -23,4 +23,3 @@ LumaWipe.Type.Square="ריבוע" LumaWipe.Type.Squares="ריבועים" LumaWipe.Type.Stripes="פסים" LumaWipe.Type.Watercolor="צבע מים" - diff --git a/plugins/obs-transitions/data/locale/hr-HR.ini b/plugins/obs-transitions/data/locale/hr-HR.ini index b277847..4a62776 100644 --- a/plugins/obs-transitions/data/locale/hr-HR.ini +++ b/plugins/obs-transitions/data/locale/hr-HR.ini @@ -48,4 +48,3 @@ 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 c984985..e2c552e 100644 --- a/plugins/obs-transitions/data/locale/hu-HU.ini +++ b/plugins/obs-transitions/data/locale/hu-HU.ini @@ -63,4 +63,4 @@ AudioMonitoring="Hangfigyelés" AudioMonitoring.None="Figyelés kikapcsolása" AudioMonitoring.MonitorOnly="Csak figyelés (kimenet némítása)" AudioMonitoring.Both="Figyelés és kimenet" - +HardwareDecode="Hardveres dekódolás használata, ha rendelkezésre áll" diff --git a/plugins/obs-transitions/data/locale/id-ID.ini b/plugins/obs-transitions/data/locale/id-ID.ini index 46c8c3b..d8aa5ff 100644 --- a/plugins/obs-transitions/data/locale/id-ID.ini +++ b/plugins/obs-transitions/data/locale/id-ID.ini @@ -63,4 +63,4 @@ AudioMonitoring="Monitoring Audio" AudioMonitoring.None="Monitor Mati" AudioMonitoring.MonitorOnly="Monitor Saja (bisukan output)" AudioMonitoring.Both="Monitor dan Output" - +HardwareDecode="Gunakan decoding perangkat keras saat tersedia" diff --git a/plugins/obs-transitions/data/locale/it-IT.ini b/plugins/obs-transitions/data/locale/it-IT.ini index c0eff1d..1f74b7b 100644 --- a/plugins/obs-transitions/data/locale/it-IT.ini +++ b/plugins/obs-transitions/data/locale/it-IT.ini @@ -63,4 +63,4 @@ AudioMonitoring="Monitoraggio audio" AudioMonitoring.None="Disattivato" AudioMonitoring.MonitorOnly="Solo monitoraggio (uscita audio nel file disattivata)" AudioMonitoring.Both="Monitora l'audio e invia all'uscita" - +HardwareDecode="Utilizza l'accellerazione hardware quando disponibile" diff --git a/plugins/obs-transitions/data/locale/ja-JP.ini b/plugins/obs-transitions/data/locale/ja-JP.ini index 097376b..b8e9ba8 100644 --- a/plugins/obs-transitions/data/locale/ja-JP.ini +++ b/plugins/obs-transitions/data/locale/ja-JP.ini @@ -63,4 +63,4 @@ AudioMonitoring="音声モニタリング" AudioMonitoring.None="モニターオフ" AudioMonitoring.MonitorOnly="モニターのみ (出力はミュート)" AudioMonitoring.Both="モニターと出力" - +HardwareDecode="利用可能な場合はハードウェアデコードを使用する" diff --git a/plugins/obs-transitions/data/locale/ka-GE.ini b/plugins/obs-transitions/data/locale/ka-GE.ini index fe2ff24..42246f3 100644 --- a/plugins/obs-transitions/data/locale/ka-GE.ini +++ b/plugins/obs-transitions/data/locale/ka-GE.ini @@ -63,4 +63,4 @@ AudioMonitoring="ხმის მოსმენა" AudioMonitoring.None="მოსმენის გარეშე" AudioMonitoring.MonitorOnly="მხოლოდ მოსმენა (უხმო გამოტანა)" AudioMonitoring.Both="მოსმენა და გამოტანა" - +HardwareDecode="აპარატურული გაშიფვრის გამოყენება, როცა ხელმისაწვდომია" diff --git a/plugins/obs-transitions/data/locale/kab-KAB.ini b/plugins/obs-transitions/data/locale/kab-KAB.ini new file mode 100644 index 0000000..e431af2 --- /dev/null +++ b/plugins/obs-transitions/data/locale/kab-KAB.ini @@ -0,0 +1,24 @@ +CutTransition="Gzem" +SlideTransition="Tamaccagt" +Direction="Tanila" +Direction.Left="Azelmaḍ" +Direction.Right="Ayfus" +Direction.Up="Asawen" +Direction.Down="Akessar" +Color="Ini" +VideoFile="Ifuyla n uvidyu" +TransitionPoint="Tanqiḍt n usaka" +TransitionPointFrame="Tanqiḍt n usaka (akatar)" +TransitionPointType="Anaw n tenqiḍt n usaka" +TransitionPointTypeFrame="Akatar" +TransitionPointTypeTime="Akud (militasinin)" +LumaWipe.Image="Tugna" +LumaWipe.Invert="Tti" +LumaWipe.Type.BoxBottomRight="Tankult ukessar s ayfus" +LumaWipe.Type.BoxTopLeft="Tankult ukessawen s azelmaḍ" +LumaWipe.Type.BoxTopRight="Tankult ukessawen s ayfus" +LumaWipe.Type.Circles="Tiwinas" +LumaWipe.Type.Clock="Tamrint" +LumaWipe.Type.Cloud="Asigna" +LumaWipe.Type.Square="Amkuẓ" +LumaWipe.Type.Squares="Imkuẓen" diff --git a/plugins/obs-transitions/data/locale/ko-KR.ini b/plugins/obs-transitions/data/locale/ko-KR.ini index 6c4c4d0..96bc1e9 100644 --- a/plugins/obs-transitions/data/locale/ko-KR.ini +++ b/plugins/obs-transitions/data/locale/ko-KR.ini @@ -63,4 +63,4 @@ AudioMonitoring="소리 감시" AudioMonitoring.None="감시 끄기" AudioMonitoring.MonitorOnly="감시만 하기 (출력은 음소거)" AudioMonitoring.Both="감시와 출력 모두" - +HardwareDecode="가능한 경우 하드웨어 디코딩 사용" diff --git a/plugins/obs-transitions/data/locale/nb-NO.ini b/plugins/obs-transitions/data/locale/nb-NO.ini index f8f685a..ad0c0b7 100644 --- a/plugins/obs-transitions/data/locale/nb-NO.ini +++ b/plugins/obs-transitions/data/locale/nb-NO.ini @@ -63,4 +63,3 @@ AudioMonitoring="Lydovervåking" AudioMonitoring.None="Av for skjermen" AudioMonitoring.MonitorOnly="Kun skjermen (Demp utdataen)" AudioMonitoring.Both="Både skjermen og utdataen" - diff --git a/plugins/obs-transitions/data/locale/nl-NL.ini b/plugins/obs-transitions/data/locale/nl-NL.ini index dad1723..530efa4 100644 --- a/plugins/obs-transitions/data/locale/nl-NL.ini +++ b/plugins/obs-transitions/data/locale/nl-NL.ini @@ -63,4 +63,4 @@ AudioMonitoring="Audio monitoring" AudioMonitoring.None="Niet monitoren" AudioMonitoring.MonitorOnly="Alleen monitoren (uitvoer gedempt)" AudioMonitoring.Both="Monitoren en uitvoeren" - +HardwareDecode="Gebruik hardware-decoding wanneer mogelijk" diff --git a/plugins/obs-transitions/data/locale/pl-PL.ini b/plugins/obs-transitions/data/locale/pl-PL.ini index d9e116f..d51c4d0 100644 --- a/plugins/obs-transitions/data/locale/pl-PL.ini +++ b/plugins/obs-transitions/data/locale/pl-PL.ini @@ -63,4 +63,4 @@ AudioMonitoring="Monitorowanie urządzenia audio" AudioMonitoring.None="Wyłączone" AudioMonitoring.MonitorOnly="Tylko monitorowanie (wyjście wyłączone)" AudioMonitoring.Both="Monitorowanie i przekazywanie na wyjście" - +HardwareDecode="Użyj dekodowania sprzętowego, gdy jest dostępne" diff --git a/plugins/obs-transitions/data/locale/pt-BR.ini b/plugins/obs-transitions/data/locale/pt-BR.ini index 983598c..60a88e8 100644 --- a/plugins/obs-transitions/data/locale/pt-BR.ini +++ b/plugins/obs-transitions/data/locale/pt-BR.ini @@ -3,7 +3,7 @@ CutTransition="Cortar" SwipeTransition="Deslizar" SlideTransition="Deslizar" StingerTransition="Stinger" -FadeToColorTransition="Esmaecer para a Cor" +FadeToColorTransition="Esmaecer para cor" Direction="Direção" Direction.Left="Esquerda" Direction.Right="Direita" @@ -14,21 +14,21 @@ Color="Cor" VideoFile="Arquivo de Vídeo" TransitionPoint="Ponto de transição" TransitionPointFrame="Ponto de transição (quadro)" -TransitionPointType="Tipo de Ponto de Transição" +TransitionPointType="Tipo de ponto de transição" TransitionPointTypeFrame="Quadro" TransitionPointTypeTime="Tempo (milissegundos)" AudioFadeStyle="Estilo de Esmaecimento de Áudio" AudioFadeStyle.FadeOutFadeIn="Esmaecer imagem até o ponto de transição e depois aparecer" -AudioFadeStyle.CrossFade="Transição Suave" +AudioFadeStyle.CrossFade="Transição suave" SwitchPoint="Ponto de cor do pico" 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.BarndoorHorizontal="Barndoor horizontal" LumaWipe.Type.BarndoorTopLeft="Barndoor inferior esquerdo" -LumaWipe.Type.BarndoorVertical="Barndoor Vertical" +LumaWipe.Type.BarndoorVertical="Barndoor vertical" LumaWipe.Type.BlindsHorizontal="Persianas horizontais" LumaWipe.Type.BoxBottomLeft="Caixa Inferior Esquerda" LumaWipe.Type.BoxBottomRight="Caixa Inferior Direita" @@ -59,8 +59,8 @@ LumaWipe.Type.StripsVertical="Listras Verticais" LumaWipe.Type.Watercolor="Aquarela" LumaWipe.Type.ZigzagHorizontal="Zigue-zague Horizontal" LumaWipe.Type.ZigzagVertical="Zigue-zague Vertical" -AudioMonitoring="Monitoramento de Áudio" +AudioMonitoring="Monitoramento de áudio" AudioMonitoring.None="Não Monitorar" AudioMonitoring.MonitorOnly="Apenas Monitorar (saída muda)" AudioMonitoring.Both="Monitorar e Enviar Áudio" - +HardwareDecode="Utilizar decodificação de hardware quando disponível" diff --git a/plugins/obs-transitions/data/locale/pt-PT.ini b/plugins/obs-transitions/data/locale/pt-PT.ini index f272738..996f024 100644 --- a/plugins/obs-transitions/data/locale/pt-PT.ini +++ b/plugins/obs-transitions/data/locale/pt-PT.ini @@ -36,4 +36,3 @@ AudioMonitoring="Monitorização de Áudio" AudioMonitoring.None="Não Monitorar" AudioMonitoring.MonitorOnly="Único Monitor (saída muda)" AudioMonitoring.Both="Monitor e Saída" - diff --git a/plugins/obs-transitions/data/locale/ro-RO.ini b/plugins/obs-transitions/data/locale/ro-RO.ini index f114cbf..da48d01 100644 --- a/plugins/obs-transitions/data/locale/ro-RO.ini +++ b/plugins/obs-transitions/data/locale/ro-RO.ini @@ -29,4 +29,3 @@ AudioMonitoring="Monitorizare audio" AudioMonitoring.None="Monitorizare dezactivată" AudioMonitoring.MonitorOnly="Numai monitorizare (amuțește outputul)" AudioMonitoring.Both="Monitorizare și output" - diff --git a/plugins/obs-transitions/data/locale/ru-RU.ini b/plugins/obs-transitions/data/locale/ru-RU.ini index ade3698..0b18d04 100644 --- a/plugins/obs-transitions/data/locale/ru-RU.ini +++ b/plugins/obs-transitions/data/locale/ru-RU.ini @@ -63,4 +63,4 @@ AudioMonitoring="Прослушивание аудио" AudioMonitoring.None="Выключить прослушивание" AudioMonitoring.MonitorOnly="Только прослушивание (заглушить вывод)" AudioMonitoring.Both="Прослушивание и вывод" - +HardwareDecode="По возможности использовать аппаратное декодирование" diff --git a/plugins/obs-transitions/data/locale/sk-SK.ini b/plugins/obs-transitions/data/locale/sk-SK.ini index c059f9a..efb1449 100644 --- a/plugins/obs-transitions/data/locale/sk-SK.ini +++ b/plugins/obs-transitions/data/locale/sk-SK.ini @@ -63,4 +63,4 @@ AudioMonitoring="Monitorovanie zvuku" AudioMonitoring.None="Vypnuté monitorovanie" AudioMonitoring.MonitorOnly="Iba monitorovanie (žiaden výstup)" AudioMonitoring.Both="Monitorovanie a výstup" - +HardwareDecode="Použiť hardvérové dekódovanie podľa dostupnosti" diff --git a/plugins/obs-transitions/data/locale/sl-SI.ini b/plugins/obs-transitions/data/locale/sl-SI.ini index 02f3bf0..7800908 100644 --- a/plugins/obs-transitions/data/locale/sl-SI.ini +++ b/plugins/obs-transitions/data/locale/sl-SI.ini @@ -63,4 +63,4 @@ AudioMonitoring="Nadzor zvoka" AudioMonitoring.None="Nadzor je izklopljen" AudioMonitoring.MonitorOnly="Samo nadziraj (utišaj izhod)" AudioMonitoring.Both="Nadzor in izhod" - +HardwareDecode="Uporabi strojno dekodiranje, če je na voljo" diff --git a/plugins/obs-transitions/data/locale/sr-CS.ini b/plugins/obs-transitions/data/locale/sr-CS.ini index 9abc1a5..fb4a7f4 100644 --- a/plugins/obs-transitions/data/locale/sr-CS.ini +++ b/plugins/obs-transitions/data/locale/sr-CS.ini @@ -61,4 +61,3 @@ AudioMonitoring="Audio nadzor" AudioMonitoring.None="Monitor je isključen" AudioMonitoring.MonitorOnly="Uključen je samo monitor (isključen je zvuk)" AudioMonitoring.Both="Uključeni su i monitor i zvuk" - diff --git a/plugins/obs-transitions/data/locale/sr-SP.ini b/plugins/obs-transitions/data/locale/sr-SP.ini index f28ba5d..a7df11c 100644 --- a/plugins/obs-transitions/data/locale/sr-SP.ini +++ b/plugins/obs-transitions/data/locale/sr-SP.ini @@ -61,4 +61,3 @@ AudioMonitoring="Аудио надзор" AudioMonitoring.None="Монитор је искључен" AudioMonitoring.MonitorOnly="Укључен је само монитор (искључен је звук)" AudioMonitoring.Both="Укључени су и монитор и звук" - diff --git a/plugins/obs-transitions/data/locale/sv-SE.ini b/plugins/obs-transitions/data/locale/sv-SE.ini index 57badbe..14a3ff3 100644 --- a/plugins/obs-transitions/data/locale/sv-SE.ini +++ b/plugins/obs-transitions/data/locale/sv-SE.ini @@ -63,4 +63,4 @@ AudioMonitoring="Ljudövervakning" AudioMonitoring.None="Övervaka inte" AudioMonitoring.MonitorOnly="Övervaka endast (tysta utgång)" AudioMonitoring.Both="Övervaka och mata ut" - +HardwareDecode="Använd hårdvaruavkodning när det är tillgängligt" diff --git a/plugins/obs-transitions/data/locale/ta-IN.ini b/plugins/obs-transitions/data/locale/ta-IN.ini index 1eaca6b..1f40888 100644 --- a/plugins/obs-transitions/data/locale/ta-IN.ini +++ b/plugins/obs-transitions/data/locale/ta-IN.ini @@ -17,4 +17,3 @@ LumaWipe.Type.Cloud="மேகம்" LumaWipe.Type.Fan="மின்விசிறி" LumaWipe.Type.Square="சதுரம்" LumaWipe.Type.Squares="சதுரன்கள்" - diff --git a/plugins/obs-transitions/data/locale/tl-PH.ini b/plugins/obs-transitions/data/locale/tl-PH.ini index 84c39c5..410f30b 100644 --- a/plugins/obs-transitions/data/locale/tl-PH.ini +++ b/plugins/obs-transitions/data/locale/tl-PH.ini @@ -61,4 +61,3 @@ AudioMonitoring="Pag-monitor sa audio" AudioMonitoring.None="Patayin ang Monitor" AudioMonitoring.MonitorOnly="Monitor lamang (i-mute ang output)" AudioMonitoring.Both="Monitor at Output" - diff --git a/plugins/obs-transitions/data/locale/tr-TR.ini b/plugins/obs-transitions/data/locale/tr-TR.ini index fa8acf1..dfb6717 100644 --- a/plugins/obs-transitions/data/locale/tr-TR.ini +++ b/plugins/obs-transitions/data/locale/tr-TR.ini @@ -63,4 +63,4 @@ AudioMonitoring="Ses İzleme" AudioMonitoring.None="Ekran Kapalı" AudioMonitoring.MonitorOnly="Sadece Ekran (sessiz çıkış)" AudioMonitoring.Both="Ekran ve Çıkış" - +HardwareDecode="Kullanılabilir olduğunda donanım çözümlemeyi kullan" diff --git a/plugins/obs-transitions/data/locale/uk-UA.ini b/plugins/obs-transitions/data/locale/uk-UA.ini index 986a514..33672e9 100644 --- a/plugins/obs-transitions/data/locale/uk-UA.ini +++ b/plugins/obs-transitions/data/locale/uk-UA.ini @@ -63,4 +63,4 @@ AudioMonitoring="Прослуховування звуку" AudioMonitoring.None="Прослуховування вимкнено" AudioMonitoring.MonitorOnly="Тільки прослуховування (заглушити вивід)" AudioMonitoring.Both="Прослуховування та вивід" - +HardwareDecode="Використовувати апаратне декодування при наявності" diff --git a/plugins/obs-transitions/data/locale/vi-VN.ini b/plugins/obs-transitions/data/locale/vi-VN.ini index 460eef1..7774023 100644 --- a/plugins/obs-transitions/data/locale/vi-VN.ini +++ b/plugins/obs-transitions/data/locale/vi-VN.ini @@ -2,6 +2,7 @@ FadeTransition="Mờ dần" CutTransition="Cắt" SwipeTransition="Vuốt" SlideTransition="Trượt" +FadeToColorTransition="Phai màu" Direction="Hướng" Direction.Left="Trái" Direction.Right="Phải" @@ -10,11 +11,28 @@ Direction.Down="Xuống" SwipeIn="Trượt lên" Color="Màu" VideoFile="Tập tin video" +TransitionPoint="Điểm chuyển cảnh" +TransitionPointFrame="Điểm chuyển cảnh (khung hình)" +TransitionPointType="Loại điểm chuyển cảnh" TransitionPointTypeFrame="Khung hình" +TransitionPointTypeTime="Thời gian (mili giây)" +AudioFadeStyle="Hiệu ứng làm mờ âm thanh" +AudioFadeStyle.FadeOutFadeIn="Mờ dần đến điểm chuyển cảnh sau đó rõ lại" AudioFadeStyle.CrossFade="Làm mờ ảnh" +SwitchPoint="Cao điểm màu" LumaWipe.Image="Hình ảnh" LumaWipe.Invert="Đảo ngược" +LumaWipe.Softness="Độ mềm" +LumaWipe.Type.Burst="Nổ" +LumaWipe.Type.Circles="Vòng tròn" +LumaWipe.Type.Clock="Đồng hồ" +LumaWipe.Type.Cloud="Mây" +LumaWipe.Type.Curtain="Màn che" +LumaWipe.Type.Fan="Quạt" +LumaWipe.Type.Fractal="Chiết hình" +LumaWipe.Type.Spiral="Xoắn ốc" LumaWipe.Type.Square="Vuông" LumaWipe.Type.Squares="Vuông" LumaWipe.Type.Stripes="Sọc" - +LumaWipe.Type.ZigzagHorizontal="Dích-dắc ngang" +LumaWipe.Type.ZigzagVertical="Dích-dắc dọc" diff --git a/plugins/obs-transitions/data/locale/zh-CN.ini b/plugins/obs-transitions/data/locale/zh-CN.ini index 47cdc82..ad6e023 100644 --- a/plugins/obs-transitions/data/locale/zh-CN.ini +++ b/plugins/obs-transitions/data/locale/zh-CN.ini @@ -63,4 +63,4 @@ AudioMonitoring="音频监听" AudioMonitoring.None="关闭监听" AudioMonitoring.MonitorOnly="仅监听(不输出音频)" AudioMonitoring.Both="监听并输出" - +HardwareDecode="优先使用硬件解码" diff --git a/plugins/obs-transitions/data/locale/zh-TW.ini b/plugins/obs-transitions/data/locale/zh-TW.ini index e77c1b0..e85ccbe 100644 --- a/plugins/obs-transitions/data/locale/zh-TW.ini +++ b/plugins/obs-transitions/data/locale/zh-TW.ini @@ -63,4 +63,4 @@ AudioMonitoring="音訊監測" AudioMonitoring.None="關閉監測" AudioMonitoring.MonitorOnly="僅監測(輸出靜音)" AudioMonitoring.Both="監測並輸出" - +HardwareDecode="盡可能使用硬體解碼" diff --git a/plugins/obs-transitions/transition-stinger.c b/plugins/obs-transitions/transition-stinger.c index ce50a4c..a770f3e 100644 --- a/plugins/obs-transitions/transition-stinger.c +++ b/plugins/obs-transitions/transition-stinger.c @@ -42,9 +42,11 @@ static void stinger_update(void *data, obs_data_t *settings) { struct stinger_info *s = data; const char *path = obs_data_get_string(settings, "path"); + bool hw_decode = obs_data_get_bool(settings, "hw_decode"); obs_data_t *media_settings = obs_data_create(); obs_data_set_string(media_settings, "local_file", path); + obs_data_set_bool(media_settings, "hw_decode", hw_decode); obs_source_release(s->media_source); struct dstr name; @@ -105,6 +107,11 @@ static void stinger_destroy(void *data) bfree(s); } +static void stinger_defaults(obs_data_t *settings) +{ + obs_data_set_default_bool(settings, "hw_decode", true); +} + static void stinger_video_render(void *data, gs_effect_t *effect) { struct stinger_info *s = data; @@ -322,6 +329,10 @@ static obs_properties_t *stinger_properties(void *data) obs_property_t *p = obs_properties_add_list( ppts, "tp_type", obs_module_text("TransitionPointType"), OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT); +#ifndef __APPLE__ + obs_properties_add_bool(ppts, "hw_decode", + obs_module_text("HardwareDecode")); +#endif obs_property_list_add_int(p, obs_module_text("TransitionPointTypeTime"), TIMING_TIME); obs_property_list_add_int( @@ -368,6 +379,7 @@ struct obs_source_info stinger_transition = { .create = stinger_create, .destroy = stinger_destroy, .update = stinger_update, + .get_defaults = stinger_defaults, .video_render = stinger_video_render, .audio_render = stinger_audio_render, .get_properties = stinger_properties, diff --git a/plugins/obs-x264/data/locale/de-DE.ini b/plugins/obs-x264/data/locale/de-DE.ini index e896fcd..ffaed71 100644 --- a/plugins/obs-x264/data/locale/de-DE.ini +++ b/plugins/obs-x264/data/locale/de-DE.ini @@ -4,10 +4,10 @@ BufferSize="Puffergröße" RateControl="Qualitätsregulierungsmethode" CRF="CRF" KeyframeIntervalSec="Keyframeintervall in Sek. (0 = automatisch)" -CPUPreset="CPU‐Auslastungsvoreinstellung (höher = niedrigere CPU‐Auslastung)" +CPUPreset="CPU-Auslastungsvoreinstellung (höher = niedrigere CPU-Auslastung)" Profile="Profil" Tune="Tune" None="(Nichts)" -EncoderOptions="x264‐Optionen (durch Leerzeichen getrennt)" +EncoderOptions="x264-Optionen (durch Leerzeichen getrennt)" VFR="Variable Framerate (VFR)" diff --git a/plugins/obs-x264/data/locale/kab-KAB.ini b/plugins/obs-x264/data/locale/kab-KAB.ini new file mode 100644 index 0000000..88388db --- /dev/null +++ b/plugins/obs-x264/data/locale/kab-KAB.ini @@ -0,0 +1,13 @@ +Bitrate="Aktum" +CustomBufsize="Seqdec tiddi yugnen i tkatut n weḥraz" +BufferSize="Tiddi n tkatut n uḥraz" +RateControl="Asenqed n uktum" +CRF="CRF" +KeyframeIntervalSec="Azilal n yikataren yufraren (tasinin, 0=awurman)" +CPUPreset="Azwirɣewwar n useqdec n CPU (afellay= drus n CPU)" +Profile="Amaɣnu" +Tune="Gerrez" +None="(Ulac)" +EncoderOptions="tinefrunin x264 (berzent s tallunt)" +VFR="Aktum n yikataren ameskil (VFR)" + diff --git a/plugins/obs-x264/obs-x264.c b/plugins/obs-x264/obs-x264.c index 41c782c..dfaa9f7 100644 --- a/plugins/obs-x264/obs-x264.c +++ b/plugins/obs-x264/obs-x264.c @@ -110,6 +110,7 @@ static void obs_x264_defaults(obs_data_t *settings) obs_data_set_default_string(settings, "profile", ""); obs_data_set_default_string(settings, "tune", ""); obs_data_set_default_string(settings, "x264opts", ""); + obs_data_set_default_bool(settings, "repeat_headers", false); } static inline void add_strings(obs_property_t *list, const char *const *strings) @@ -172,6 +173,7 @@ static obs_properties_t *obs_x264_props(void *unused) obs_properties_t *props = obs_properties_create(); obs_property_t *list; obs_property_t *p; + obs_property_t *headers; list = obs_properties_add_list(props, "rate_control", TEXT_RATE_CONTROL, OBS_COMBO_TYPE_LIST, @@ -222,6 +224,10 @@ static obs_properties_t *obs_x264_props(void *unused) obs_properties_add_text(props, "x264opts", TEXT_X264_OPTS, OBS_TEXT_DEFAULT); + headers = obs_properties_add_bool(props, "repeat_headers", + "repeat_headers"); + obs_property_set_visible(headers, false); + return props; } @@ -583,6 +589,7 @@ static bool update_settings(struct obs_x264 *obsx264, obs_data_t *settings, char *tune = bstrdup(obs_data_get_string(settings, "tune")); struct obs_x264_options options = obs_x264_parse_options( obs_data_get_string(settings, "x264opts")); + bool repeat_headers = obs_data_get_bool(settings, "repeat_headers"); bool success = true; @@ -603,6 +610,12 @@ static bool update_settings(struct obs_x264 *obsx264, obs_data_t *settings, success = reset_x264_params(obsx264, preset, tune); } + if (repeat_headers) { + obsx264->params.b_repeat_headers = 1; + obsx264->params.b_annexb = 1; + obsx264->params.b_aud = 1; + } + if (success) { update_params(obsx264, settings, &options, update); if (!update) { @@ -613,8 +626,6 @@ static bool update_settings(struct obs_x264 *obsx264, obs_data_t *settings, apply_x264_profile(obsx264, profile); } - obsx264->params.b_repeat_headers = false; - obs_x264_free_options(options); bfree(preset); bfree(profile); diff --git a/plugins/oss-audio/data/locale/ar-SA.ini b/plugins/oss-audio/data/locale/ar-SA.ini new file mode 100644 index 0000000..ab38e52 --- /dev/null +++ b/plugins/oss-audio/data/locale/ar-SA.ini @@ -0,0 +1,9 @@ +OSSInput="التقاط إدخال الصوت (OSS)" +DSP="DSP" +CustomDSPPath="مسار DSP مخصص" +SampleRate="معدل العينة" +Channels="القنوات" +SampleFormat="تنسيق العينة" +Default="افتراضي" +Custom="مخصص" + diff --git a/plugins/oss-audio/data/locale/de-DE.ini b/plugins/oss-audio/data/locale/de-DE.ini index 74ae103..1ddca0d 100644 --- a/plugins/oss-audio/data/locale/de-DE.ini +++ b/plugins/oss-audio/data/locale/de-DE.ini @@ -1,6 +1,6 @@ OSSInput="Audioeingabeaufnahme (OSS)" DSP="DSP" -CustomDSPPath="Benutzerdefinierter DSP‐Pfad" +CustomDSPPath="Benutzerdefinierter DSP-Pfad" SampleRate="Sample Rate" Channels="Kanäle" SampleFormat="Beispielformat" diff --git a/plugins/oss-audio/data/locale/el-GR.ini b/plugins/oss-audio/data/locale/el-GR.ini new file mode 100644 index 0000000..288d1f3 --- /dev/null +++ b/plugins/oss-audio/data/locale/el-GR.ini @@ -0,0 +1,9 @@ +OSSInput="Ηχογράφηση Εισόδου (OSS)" +DSP="DSP" +CustomDSPPath="Προσαρμοσμένη διαδρομή DSP" +SampleRate="Ρυθμός Δειγματοληψίας" +Channels="Κανάλια" +SampleFormat="Ενδεικτική μορφοποίηση" +Default="Προεπιλογή" +Custom="Προσαρμοσμένη" + diff --git a/plugins/oss-audio/data/locale/et-EE.ini b/plugins/oss-audio/data/locale/et-EE.ini new file mode 100644 index 0000000..ba75178 --- /dev/null +++ b/plugins/oss-audio/data/locale/et-EE.ini @@ -0,0 +1,9 @@ +OSSInput="Helisisendi hõive (OSS)" +DSP="DSP" +CustomDSPPath="Kohandatud DSP aadress" +SampleRate="Hetkeväärtus" +Channels="Kanalid" +SampleFormat="Näidisvorming" +Default="Vaikimisi" +Custom="Kohandatud" + diff --git a/plugins/oss-audio/data/locale/fa-IR.ini b/plugins/oss-audio/data/locale/fa-IR.ini new file mode 100644 index 0000000..7158c28 --- /dev/null +++ b/plugins/oss-audio/data/locale/fa-IR.ini @@ -0,0 +1,9 @@ +OSSInput="ضبط ورودی صوتی (س ص ب)" +DSP="پ س د" +CustomDSPPath="مسیر پ س د سفارشی" +SampleRate="نرخ نمونه" +Channels="کانال‌ها" +SampleFormat="فرمت نمونه" +Default="پیش فرض" +Custom="سفارشی" + diff --git a/plugins/oss-audio/data/locale/fil-PH.ini b/plugins/oss-audio/data/locale/fil-PH.ini index 321480a..5a9a875 100644 --- a/plugins/oss-audio/data/locale/fil-PH.ini +++ b/plugins/oss-audio/data/locale/fil-PH.ini @@ -1,5 +1,7 @@ +OSSInput="Daming Input Capture (DSS)" DSP="DSP" CustomDSPPath="Pasadyang DSP Path" Channels="Mga Channel" +Default="Orihinal" Custom="Pasadya" diff --git a/plugins/oss-audio/data/locale/ka-GE.ini b/plugins/oss-audio/data/locale/ka-GE.ini index eebc0eb..c9758fc 100644 --- a/plugins/oss-audio/data/locale/ka-GE.ini +++ b/plugins/oss-audio/data/locale/ka-GE.ini @@ -1,9 +1,9 @@ OSSInput="შემავალი ხმის ჩაწერა (OSS)" DSP="DSP" CustomDSPPath="მითითებული DSP-მდებარეობა" -SampleRate="შერჩევის სიხშირე" +SampleRate="დაყოფის სიხშირე" Channels="არხები" -SampleFormat="შერჩევის სახეობა" +SampleFormat="დაყოფის სახეობა" Default="ნაგულისხმევი" Custom="მითითებული" diff --git a/plugins/oss-audio/data/locale/kab-KAB.ini b/plugins/oss-audio/data/locale/kab-KAB.ini new file mode 100644 index 0000000..2d675c8 --- /dev/null +++ b/plugins/oss-audio/data/locale/kab-KAB.ini @@ -0,0 +1,9 @@ +OSSInput="Tuṭṭfa n unekcum n umeslaw (OSS)" +DSP="DSP" +CustomDSPPath="Abrid n DSP yugnen" +SampleRate="Atug n ulemmec" +Channels="Ibuda" +SampleFormat="Amasal n ulemmec" +Default="Amezwar" +Custom="Yugen" + diff --git a/plugins/oss-audio/data/locale/pt-BR.ini b/plugins/oss-audio/data/locale/pt-BR.ini index 02dd067..f26d8bf 100644 --- a/plugins/oss-audio/data/locale/pt-BR.ini +++ b/plugins/oss-audio/data/locale/pt-BR.ini @@ -1,4 +1,4 @@ -OSSInput="Captura de Entrada de Áudio (OSS)" +OSSInput="Captura de entrada de áudio (OSS)" DSP="DSP" CustomDSPPath="Caminho Personalizado do DSP" SampleRate="Taxa de Amostragem" diff --git a/plugins/oss-audio/data/locale/pt-PT.ini b/plugins/oss-audio/data/locale/pt-PT.ini new file mode 100644 index 0000000..89db434 --- /dev/null +++ b/plugins/oss-audio/data/locale/pt-PT.ini @@ -0,0 +1,5 @@ +DSP="DSP" +Channels="Canais" +Default="Padrão" +Custom="Personalizado" + diff --git a/plugins/oss-audio/data/locale/ro-RO.ini b/plugins/oss-audio/data/locale/ro-RO.ini index 48a1b23..12a1d0f 100644 --- a/plugins/oss-audio/data/locale/ro-RO.ini +++ b/plugins/oss-audio/data/locale/ro-RO.ini @@ -1,9 +1,9 @@ OSSInput="Captură de input audio (OSS)" DSP="DSP" CustomDSPPath="Cale personalizată DSP" -SampleRate="Rata de eşantionare" +SampleRate="Rată de eşantionare" Channels="Canale" -SampleFormat="Mostră format" +SampleFormat="Format de eșantionare" Default="Implicită" Custom="Personalizat" diff --git a/plugins/rtmp-services/data/locale/ar-SA.ini b/plugins/rtmp-services/data/locale/ar-SA.ini index 74ab695..b082177 100644 --- a/plugins/rtmp-services/data/locale/ar-SA.ini +++ b/plugins/rtmp-services/data/locale/ar-SA.ini @@ -2,6 +2,7 @@ StreamingServices="خدمات البث" CustomStreamingServer="سيرفر بث مخصص" Service="خدمة" Server="سيرفر" +Server.Auto="تلقائي (مستحسن)" StreamKey="مفتاح البث" UseAuth="استخدام المصادقة" Username="اسم المستخدم" diff --git a/plugins/rtmp-services/data/locale/kab-KAB.ini b/plugins/rtmp-services/data/locale/kab-KAB.ini new file mode 100644 index 0000000..3f377a6 --- /dev/null +++ b/plugins/rtmp-services/data/locale/kab-KAB.ini @@ -0,0 +1,11 @@ +StreamingServices="Imeẓluyen n usuddem" +CustomStreamingServer="Aqeddac n usuddem yugnen" +Service="Imeẓluyen" +Server="Aqeddac" +Server.Auto="Awurman (Yettwasemter)" +StreamKey="Tasarut n usuddem" +UseAuth="Seqdec asesteb" +Username="Isem n useqdac" +Password="Awal uffir" +ShowAll="Sken akk imeẓluyen" + diff --git a/plugins/rtmp-services/data/locale/sv-SE.ini b/plugins/rtmp-services/data/locale/sv-SE.ini index 54ae360..b3b0ea6 100644 --- a/plugins/rtmp-services/data/locale/sv-SE.ini +++ b/plugins/rtmp-services/data/locale/sv-SE.ini @@ -1,5 +1,5 @@ StreamingServices="Strömtjänster" -CustomStreamingServer="Anpassad streamningsserver" +CustomStreamingServer="Anpassad strömningsserver" Service="Tjänst" Server="Server" Server.Auto="Auto (rekommenderad)" diff --git a/plugins/rtmp-services/data/package.json b/plugins/rtmp-services/data/package.json index d1195ee..0a9c2dd 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": 148, + "version": 161, "files": [ { "name": "services.json", - "version": 148 + "version": 161 } ] } diff --git a/plugins/rtmp-services/data/services.json b/plugins/rtmp-services/data/services.json index 6fbdf29..6e9ca4a 100644 --- a/plugins/rtmp-services/data/services.json +++ b/plugins/rtmp-services/data/services.json @@ -1,5 +1,5 @@ { - "format_version": 2, + "format_version": 3, "services": [ { "name": "Twitch", @@ -193,13 +193,37 @@ "recommended": { "keyint": 2, "max video bitrate": 6000, - "max audio bitrate": 160, + "max audio bitrate": 320, "x264opts": "scenecut=0" } }, { - "name": "YouTube / YouTube Gaming", + "name": "YouTube - HLS", + "common": false, + "more_info_link": "https://developers.google.com/youtube/v3/live/guides/ingestion-protocol-comparison", + "servers": [ + { + "name": "Primary YouTube ingest server", + "url": "https://a.upload.youtube.com/http_upload_hls?cid={stream_key}©=0&file=out.m3u8" + }, + { + "name": "Backup YouTube ingest server", + "url": "https://b.upload.youtube.com/http_upload_hls?cid={stream_key}©=1&file=out.m3u8" + } + ], + "recommended": { + "keyint": 2, + "output": "ffmpeg_hls_muxer", + "max video bitrate": 51000, + "max audio bitrate": 160 + } + }, + { + "name": "YouTube - RTMP", "common": true, + "alt_names": [ + "YouTube / YouTube Gaming" + ], "servers": [ { "name": "Primary YouTube ingest server", @@ -216,6 +240,25 @@ "max audio bitrate": 160 } }, + { + "name": "YouTube - RTMPS (Beta)", + "common": true, + "servers": [ + { + "name": "Primary YouTube ingest server", + "url": "rtmps://a.rtmps.youtube.com:443/live2" + }, + { + "name": "Backup YouTube ingest server", + "url": "rtmps://b.rtmps.youtube.com:443/live2" + } + ], + "recommended": { + "keyint": 2, + "max video bitrate": 51000, + "max audio bitrate": 160 + } + }, { "name": "VIMM", "servers": [ @@ -434,6 +477,12 @@ "recommended": { "keyint": 2, "profile": "main", + "supported resolutions": [ + "1280x720", + "852x480", + "480x360" + ], + "max fps": 30, "max video bitrate": 6000, "max audio bitrate": 128 } @@ -1409,52 +1458,8 @@ "common": false, "servers": [ { - "name": "Chicago, US", - "url": "rtmp://ingest-any-ord1.broadcast.steamcontent.com/app" - }, - { - "name": "Seattle, US", - "url": "rtmp://ingest-any-sea1.broadcast.steamcontent.com/app" - }, - { - "name": "Los Angeles, US", - "url": "rtmp://ingest-any-lax1.broadcast.steamcontent.com/app" - }, - { - "name": "Washington DC, US", - "url": "rtmp://ingest-any-iad1.broadcast.steamcontent.com/app" - }, - { - "name": "Frankfurt, DE", - "url": "rtmp://ingest-any-fra1.broadcast.steamcontent.com/app" - }, - { - "name": "London, UK", - "url": "rtmp://ingest-any-lhr1.broadcast.steamcontent.com/app" - }, - { - "name": "Stockholm, SE", - "url": "rtmp://ingest-any-sto1.broadcast.steamcontent.com/app" - }, - { - "name": "Tokyo, JP", - "url": "rtmp://ingest-any-tyo1.broadcast.steamcontent.com/app" - }, - { - "name": "Hong Kong, HK", - "url": "rtmp://ingest-any-hkg1.broadcast.steamcontent.com/app" - }, - { - "name": "Singapore, SG", - "url": "rtmp://ingest-any-sgp1.broadcast.steamcontent.com/app" - }, - { - "name": "Sydney, AU", - "url": "rtmp://ingest-any-syd1.broadcast.steamcontent.com/app" - }, - { - "name": "São Paulo, BR", - "url": "rtmp://ingest-any-gru1.broadcast.steamcontent.com/app" + "name": "Default", + "url": "rtmp://ingest-rtmp.broadcast.steamcontent.com/app" } ], "recommended": { @@ -1792,6 +1797,20 @@ "max video bitrate": 5000, "max audio bitrate": 160 } + }, + { + "name": "Viloud", + "servers": [ + { + "name": "Default", + "url": "rtmp://live.viloud.tv:5222/app" + } + ], + "recommended": { + "keyint": 2, + "max video bitrate": 5000, + "max audio bitrate": 160 + } } ] } diff --git a/plugins/rtmp-services/rtmp-common.c b/plugins/rtmp-services/rtmp-common.c index 5c25276..2284a6c 100644 --- a/plugins/rtmp-services/rtmp-common.c +++ b/plugins/rtmp-services/rtmp-common.c @@ -16,6 +16,9 @@ struct rtmp_common { char *key; char *output; + struct obs_service_resolution *supported_resolutions; + size_t supported_resolutions_count; + int max_fps; bool supports_additional_audio_track; }; @@ -31,6 +34,7 @@ static inline json_t *find_service(json_t *root, const char *name, const char **p_new_name); static inline bool get_bool_val(json_t *service, const char *key); static inline const char *get_string_val(json_t *service, const char *key); +static inline int get_int_val(json_t *service, const char *key); extern void twitch_ingests_refresh(int seconds); @@ -67,6 +71,43 @@ static void ensure_valid_url(struct rtmp_common *service, json_t *json, } } +static void update_recommendations(struct rtmp_common *service, json_t *rec) +{ + const char *out = get_string_val(rec, "output"); + if (out) + service->output = bstrdup(out); + + json_t *sr = json_object_get(rec, "supported resolutions"); + if (sr && json_is_array(sr)) { + DARRAY(struct obs_service_resolution) res_list; + json_t *res_obj; + size_t index; + + da_init(res_list); + + json_array_foreach (sr, index, res_obj) { + if (!json_is_string(res_obj)) + continue; + + const char *res_str = json_string_value(res_obj); + struct obs_service_resolution res; + if (sscanf(res_str, "%dx%d", &res.cx, &res.cy) != 2) + continue; + if (res.cx <= 0 || res.cy <= 0) + continue; + + da_push_back(res_list, &res); + } + + if (res_list.num) { + service->supported_resolutions = res_list.array; + service->supported_resolutions_count = res_list.num; + } + } + + service->max_fps = get_int_val(rec, "max fps"); +} + static void rtmp_common_update(void *data, obs_data_t *settings) { struct rtmp_common *service = data; @@ -75,12 +116,16 @@ static void rtmp_common_update(void *data, obs_data_t *settings) bfree(service->server); bfree(service->output); bfree(service->key); + bfree(service->supported_resolutions); service->service = bstrdup(obs_data_get_string(settings, "service")); service->server = bstrdup(obs_data_get_string(settings, "server")); service->key = bstrdup(obs_data_get_string(settings, "key")); service->supports_additional_audio_track = false; service->output = NULL; + service->supported_resolutions = NULL; + service->supported_resolutions_count = 0; + service->max_fps = 0; json_t *root = open_services_file(); if (root) { @@ -95,9 +140,7 @@ static void rtmp_common_update(void *data, obs_data_t *settings) if (serv) { json_t *rec = json_object_get(serv, "recommended"); if (json_is_object(rec)) { - const char *out = get_string_val(rec, "output"); - if (out) - service->output = bstrdup(out); + update_recommendations(service, rec); } service->supports_additional_audio_track = get_bool_val( @@ -115,6 +158,7 @@ static void rtmp_common_destroy(void *data) { struct rtmp_common *service = data; + bfree(service->supported_resolutions); bfree(service->service); bfree(service->server); bfree(service->output); @@ -370,6 +414,15 @@ static void fill_servers(obs_property_t *servers_prop, json_t *service, } } +static void fill_more_info_link(json_t *service, obs_data_t *settings) +{ + const char *more_info_link; + + more_info_link = get_string_val(service, "more_info_link"); + if (more_info_link) + obs_data_set_string(settings, "more_info_link", more_info_link); +} + static inline json_t *find_service(json_t *root, const char *name, const char **p_new_name) { @@ -432,7 +485,7 @@ static bool service_selected(obs_properties_t *props, obs_property_t *p, } fill_servers(obs_properties_get(props, "server"), service, name); - + fill_more_info_link(service, settings); return true; } @@ -516,7 +569,7 @@ static void apply_video_encoder_settings(obs_data_t *settings, item = json_object_get(recommended, "bframes"); if (json_is_integer(item)) { - int bframes = json_integer_value(item); + int bframes = (int)json_integer_value(item); obs_data_set_int(settings, "bf", bframes); } @@ -654,6 +707,57 @@ static bool supports_multitrack(void *data) return service->supports_additional_audio_track; } +static void rtmp_common_get_supported_resolutions( + void *data, struct obs_service_resolution **resolutions, size_t *count) +{ + struct rtmp_common *service = data; + *count = service->supported_resolutions_count; + *resolutions = bmemdup(service->supported_resolutions, + *count * sizeof(struct obs_service_resolution)); +} + +static void rtmp_common_get_max_fps(void *data, int *fps) +{ + struct rtmp_common *service = data; + *fps = service->max_fps; +} + +static void rtmp_common_get_max_bitrate(void *data, int *video_bitrate, + int *audio_bitrate) +{ + struct rtmp_common *service = data; + json_t *root = open_services_file(); + json_t *item; + + if (!root) + return; + + json_t *json_service = find_service(root, service->service, NULL); + if (!json_service) { + goto fail; + } + + json_t *recommended = json_object_get(json_service, "recommended"); + if (!recommended) { + goto fail; + } + + if (audio_bitrate) { + item = json_object_get(recommended, "max audio bitrate"); + if (json_is_integer(item)) + *audio_bitrate = (int)json_integer_value(item); + } + + if (video_bitrate) { + item = json_object_get(recommended, "max video bitrate"); + if (json_is_integer(item)) + *video_bitrate = (int)json_integer_value(item); + } + +fail: + json_decref(root); +} + struct obs_service_info rtmp_common_service = { .id = "rtmp_common", .get_name = rtmp_common_getname, @@ -665,4 +769,7 @@ struct obs_service_info rtmp_common_service = { .get_key = rtmp_common_key, .apply_encoder_settings = rtmp_common_apply_settings, .get_output_type = rtmp_common_get_output_type, + .get_supported_resolutions = rtmp_common_get_supported_resolutions, + .get_max_fps = rtmp_common_get_max_fps, + .get_max_bitrate = rtmp_common_get_max_bitrate, }; diff --git a/plugins/rtmp-services/rtmp-custom.c b/plugins/rtmp-services/rtmp-custom.c index 921be2f..6879eb9 100644 --- a/plugins/rtmp-services/rtmp-custom.c +++ b/plugins/rtmp-services/rtmp-custom.c @@ -1,4 +1,5 @@ #include +#include struct rtmp_custom { char *server, *key; @@ -109,6 +110,19 @@ static const char *rtmp_custom_password(void *data) return service->password; } +#define RTMP_PROTOCOL "rtmp" + +static void rtmp_custom_apply_settings(void *data, obs_data_t *video_settings, + obs_data_t *audio_settings) +{ + struct rtmp_custom *service = data; + if (service->server != NULL && video_settings != NULL && + strncmp(service->server, RTMP_PROTOCOL, strlen(RTMP_PROTOCOL)) != + 0) { + obs_data_set_bool(video_settings, "repeat_headers", true); + } +} + struct obs_service_info rtmp_custom_service = { .id = "rtmp_custom", .get_name = rtmp_custom_name, @@ -120,4 +134,5 @@ struct obs_service_info rtmp_custom_service = { .get_key = rtmp_custom_key, .get_username = rtmp_custom_username, .get_password = rtmp_custom_password, + .apply_encoder_settings = rtmp_custom_apply_settings, }; diff --git a/plugins/rtmp-services/rtmp-format-ver.h b/plugins/rtmp-services/rtmp-format-ver.h index 8e4952a..8909b9a 100644 --- a/plugins/rtmp-services/rtmp-format-ver.h +++ b/plugins/rtmp-services/rtmp-format-ver.h @@ -1,3 +1,3 @@ #pragma once -#define RTMP_SERVICES_FORMAT_VERSION 2 +#define RTMP_SERVICES_FORMAT_VERSION 3 diff --git a/plugins/sndio/CMakeLists.txt b/plugins/sndio/CMakeLists.txt new file mode 100644 index 0000000..24f8d94 --- /dev/null +++ b/plugins/sndio/CMakeLists.txt @@ -0,0 +1,35 @@ +project(sndio) + +if(DISABLE_SNDIO) + message(STATUS "Sndio support disabled") + return() +endif() + +find_package(Sndio) +if(NOT Sndio_FOUND AND ENABLE_SNDIO) + message(FATAL_ERROR "Sndio not found but set as enabled") +elseif(NOT Sndio_FOUND) + message(STATUS "Sndio not found, disabling Sndio plugin") + return() +endif() + +include_directories( + SYSTEM "${CMAKE_SOURCE_DIR}/libobs" SYSTEM "${CMAKE_SOURCE_DIR}/../../libobs" + ${Sndio_INCLUDE_DIRS} +) + +set(sndio_SOURCES + sndio.c + sndio-input.c +) + +add_library(sndio MODULE + ${sndio_SOURCES} +) +target_link_libraries(sndio + libobs + ${Sndio_LIBRARIES} +) +set_target_properties(sndio PROPERTIES FOLDER "plugins") + +install_obs_plugin_with_data(sndio data) diff --git a/plugins/sndio/data/locale/ar-SA.ini b/plugins/sndio/data/locale/ar-SA.ini new file mode 100644 index 0000000..c676110 --- /dev/null +++ b/plugins/sndio/data/locale/ar-SA.ini @@ -0,0 +1,6 @@ +Channels="عدد القنوات" +Device="جهاز" +BitsPerSample="بت لكل عينة" +Rate="معدل" + + diff --git a/plugins/sndio/data/locale/ca-ES.ini b/plugins/sndio/data/locale/ca-ES.ini new file mode 100644 index 0000000..fbb5420 --- /dev/null +++ b/plugins/sndio/data/locale/ca-ES.ini @@ -0,0 +1,7 @@ +Channels="Número de canals" +Device="Dispositiu" +BitsPerSample="Bits per mostra" +Rate="Taxa" +SndioInput="Client d’entrada Sndio" + + diff --git a/plugins/sndio/data/locale/cs-CZ.ini b/plugins/sndio/data/locale/cs-CZ.ini new file mode 100644 index 0000000..2194fde --- /dev/null +++ b/plugins/sndio/data/locale/cs-CZ.ini @@ -0,0 +1,7 @@ +Channels="Počet kanálů" +Device="Zařízení" +BitsPerSample="Bitů na vzorek" +Rate="Frekvence" +SndioInput="Sndio klient" + + diff --git a/plugins/sndio/data/locale/da-DK.ini b/plugins/sndio/data/locale/da-DK.ini new file mode 100644 index 0000000..de5e03f --- /dev/null +++ b/plugins/sndio/data/locale/da-DK.ini @@ -0,0 +1,7 @@ +Channels="Antal kanaler" +Device="Enhed" +BitsPerSample="Bits pr. sample" +Rate="Hastighed" +SndioInput="Sndio-inputklient" + + diff --git a/plugins/sndio/data/locale/de-DE.ini b/plugins/sndio/data/locale/de-DE.ini new file mode 100644 index 0000000..cae1674 --- /dev/null +++ b/plugins/sndio/data/locale/de-DE.ini @@ -0,0 +1,7 @@ +Channels="Anzahl der Kanäle" +Device="Gerät" +BitsPerSample="Bits pro Sample" +Rate="Rate" +SndioInput="Sndio-Eingabeclient" + + diff --git a/plugins/sndio/data/locale/el-GR.ini b/plugins/sndio/data/locale/el-GR.ini new file mode 100644 index 0000000..55c87b0 --- /dev/null +++ b/plugins/sndio/data/locale/el-GR.ini @@ -0,0 +1,6 @@ +Channels="Αριθμός καναλιών" +Device="Συσκευή" +BitsPerSample="Bits ανά δείγμα" +Rate="Ρυθμός" + + diff --git a/plugins/sndio/data/locale/en-GB.ini b/plugins/sndio/data/locale/en-GB.ini new file mode 100644 index 0000000..419f81f --- /dev/null +++ b/plugins/sndio/data/locale/en-GB.ini @@ -0,0 +1,7 @@ +Channels="Number of channels" +Device="Device" +BitsPerSample="Bits per sample" +Rate="Rate" +SndioInput="Sndio input client" + + diff --git a/plugins/sndio/data/locale/en-US.ini b/plugins/sndio/data/locale/en-US.ini new file mode 100644 index 0000000..1d7c467 --- /dev/null +++ b/plugins/sndio/data/locale/en-US.ini @@ -0,0 +1,6 @@ +Channels="Number of channels" +Device="Device" +BitsPerSample="Bits per sample" +Rate="Rate" +SndioInput="Sndio input client" + diff --git a/plugins/sndio/data/locale/es-ES.ini b/plugins/sndio/data/locale/es-ES.ini new file mode 100644 index 0000000..b5319cf --- /dev/null +++ b/plugins/sndio/data/locale/es-ES.ini @@ -0,0 +1,7 @@ +Channels="Número de canales" +Device="Dispositivo" +BitsPerSample="Bits por muestra" +Rate="Tasa" +SndioInput="Cliente de entrada Sndio" + + diff --git a/plugins/sndio/data/locale/et-EE.ini b/plugins/sndio/data/locale/et-EE.ini new file mode 100644 index 0000000..05602e1 --- /dev/null +++ b/plugins/sndio/data/locale/et-EE.ini @@ -0,0 +1,7 @@ +Channels="Kanalite arv" +Device="Seade" +BitsPerSample="Bitti proovi" +Rate="Hinnang" +SndioInput="Sndio sisendklient" + + diff --git a/plugins/sndio/data/locale/fa-IR.ini b/plugins/sndio/data/locale/fa-IR.ini new file mode 100644 index 0000000..68e9cec --- /dev/null +++ b/plugins/sndio/data/locale/fa-IR.ini @@ -0,0 +1,7 @@ +Channels="تعداد کانال ها" +Device="دستگاه" +BitsPerSample="بیت در هر نمونه" +Rate="نرخ" +SndioInput="کلاینت ورودی Sndio" + + diff --git a/plugins/sndio/data/locale/fi-FI.ini b/plugins/sndio/data/locale/fi-FI.ini new file mode 100644 index 0000000..8c4cecf --- /dev/null +++ b/plugins/sndio/data/locale/fi-FI.ini @@ -0,0 +1,7 @@ +Channels="Kanavien määrä" +Device="Laite" +BitsPerSample="Bittiä per näyte" +Rate="Näytteenottotaajuus" +SndioInput="Sndio sisääntulon asiakas" + + diff --git a/plugins/sndio/data/locale/fr-FR.ini b/plugins/sndio/data/locale/fr-FR.ini new file mode 100644 index 0000000..10efe84 --- /dev/null +++ b/plugins/sndio/data/locale/fr-FR.ini @@ -0,0 +1,7 @@ +Channels="Nombre de canaux" +Device="Appareil" +BitsPerSample="Bits par échantillon" +Rate="Taux" +SndioInput="Entrée client Sndio" + + diff --git a/plugins/sndio/data/locale/gl-ES.ini b/plugins/sndio/data/locale/gl-ES.ini new file mode 100644 index 0000000..b2fffb4 --- /dev/null +++ b/plugins/sndio/data/locale/gl-ES.ini @@ -0,0 +1,7 @@ +Channels="Número de canles" +Device="Dispositivo" +BitsPerSample="Bits por mostra" +Rate="Taxa" +SndioInput="Cliente de entrada «sndio»" + + diff --git a/plugins/sndio/data/locale/hu-HU.ini b/plugins/sndio/data/locale/hu-HU.ini new file mode 100644 index 0000000..efb86a8 --- /dev/null +++ b/plugins/sndio/data/locale/hu-HU.ini @@ -0,0 +1,4 @@ +Channels="Csatornák száma" +Device="Eszköz" + + diff --git a/plugins/sndio/data/locale/id-ID.ini b/plugins/sndio/data/locale/id-ID.ini new file mode 100644 index 0000000..b4c6a5f --- /dev/null +++ b/plugins/sndio/data/locale/id-ID.ini @@ -0,0 +1,7 @@ +Channels="Jumlah saluran" +Device="Perangkat" +BitsPerSample="Bit per sampel" +Rate="Nilai" +SndioInput="Input klien Sndio" + + diff --git a/plugins/sndio/data/locale/it-IT.ini b/plugins/sndio/data/locale/it-IT.ini new file mode 100644 index 0000000..08452cd --- /dev/null +++ b/plugins/sndio/data/locale/it-IT.ini @@ -0,0 +1,7 @@ +Channels="Numero di canali" +Device="Dispositivo" +BitsPerSample="Bit per campione" +Rate="Velocità" +SndioInput="Client di ingresso sndio" + + diff --git a/plugins/sndio/data/locale/ja-JP.ini b/plugins/sndio/data/locale/ja-JP.ini new file mode 100644 index 0000000..c4e8ab4 --- /dev/null +++ b/plugins/sndio/data/locale/ja-JP.ini @@ -0,0 +1,7 @@ +Channels="チャネル数" +Device="デバイス" +BitsPerSample="ビット毎サンプル" +Rate="レート" +SndioInput="Sndio入力クライアント" + + diff --git a/plugins/sndio/data/locale/ka-GE.ini b/plugins/sndio/data/locale/ka-GE.ini new file mode 100644 index 0000000..b42faa9 --- /dev/null +++ b/plugins/sndio/data/locale/ka-GE.ini @@ -0,0 +1,7 @@ +Channels="არხების რაოდენობა" +Device="მოწყობილობა" +BitsPerSample="ბიტი დანაყოფში" +Rate="სიხშირე" +SndioInput="Sndio-შეტანის კლიენტი" + + diff --git a/plugins/sndio/data/locale/kab-KAB.ini b/plugins/sndio/data/locale/kab-KAB.ini new file mode 100644 index 0000000..3e05b25 --- /dev/null +++ b/plugins/sndio/data/locale/kab-KAB.ini @@ -0,0 +1,7 @@ +Channels="Amḍan n ibuda" +Device="Ibenk" +BitsPerSample="Ibiten i tlemmict" +Rate="Atug" +SndioInput="Anekcum Sndio n umsaɣ" + + diff --git a/plugins/sndio/data/locale/ko-KR.ini b/plugins/sndio/data/locale/ko-KR.ini new file mode 100644 index 0000000..9435678 --- /dev/null +++ b/plugins/sndio/data/locale/ko-KR.ini @@ -0,0 +1,7 @@ +Channels="채널 수" +Device="장치" +BitsPerSample="샘플 당 비트 수" +Rate="샘플링 레이트" +SndioInput="입력 클라이언트" + + diff --git a/plugins/sndio/data/locale/nl-NL.ini b/plugins/sndio/data/locale/nl-NL.ini new file mode 100644 index 0000000..b577009 --- /dev/null +++ b/plugins/sndio/data/locale/nl-NL.ini @@ -0,0 +1,7 @@ +Channels="Aantal kanalen" +Device="Apparaat" +BitsPerSample="Bits per sample" +Rate="Rate" +SndioInput="Sndio input client" + + diff --git a/plugins/sndio/data/locale/pl-PL.ini b/plugins/sndio/data/locale/pl-PL.ini new file mode 100644 index 0000000..1e776d1 --- /dev/null +++ b/plugins/sndio/data/locale/pl-PL.ini @@ -0,0 +1,7 @@ +Channels="Liczba kanałów" +Device="Urządzenie" +BitsPerSample="Bity na próbkę" +Rate="Częstotliwość próbkowania" +SndioInput="Klient Sndio - wejście" + + diff --git a/plugins/sndio/data/locale/pt-BR.ini b/plugins/sndio/data/locale/pt-BR.ini new file mode 100644 index 0000000..83d73c7 --- /dev/null +++ b/plugins/sndio/data/locale/pt-BR.ini @@ -0,0 +1,7 @@ +Channels="Número de canais" +Device="Dispositivo" +BitsPerSample="Bits por amostra" +Rate="Taxa" +SndioInput="Cliente de inserção sndio" + + diff --git a/plugins/sndio/data/locale/pt-PT.ini b/plugins/sndio/data/locale/pt-PT.ini new file mode 100644 index 0000000..90a5cfb --- /dev/null +++ b/plugins/sndio/data/locale/pt-PT.ini @@ -0,0 +1,5 @@ +Channels="Número de canais" +Device="Dispositivo" +BitsPerSample="Bits por amostra" + + diff --git a/plugins/sndio/data/locale/ru-RU.ini b/plugins/sndio/data/locale/ru-RU.ini new file mode 100644 index 0000000..020bedb --- /dev/null +++ b/plugins/sndio/data/locale/ru-RU.ini @@ -0,0 +1,7 @@ +Channels="Количество каналов" +Device="Устройство" +BitsPerSample="Биты на образец" +Rate="Ставка" +SndioInput="Клиент ввода Sndio" + + diff --git a/plugins/sndio/data/locale/sk-SK.ini b/plugins/sndio/data/locale/sk-SK.ini new file mode 100644 index 0000000..4bf2ea3 --- /dev/null +++ b/plugins/sndio/data/locale/sk-SK.ini @@ -0,0 +1,7 @@ +Channels="Počet kanálov" +Device="Zariadenie" +BitsPerSample="Bitov na vzorku" +Rate="Frekvencia" +SndioInput="Sndio klient vstupu" + + diff --git a/plugins/sndio/data/locale/sl-SI.ini b/plugins/sndio/data/locale/sl-SI.ini new file mode 100644 index 0000000..22efca1 --- /dev/null +++ b/plugins/sndio/data/locale/sl-SI.ini @@ -0,0 +1,7 @@ +Channels="Število kanalov" +Device="Naprava" +BitsPerSample="Bitov na vzorec" +Rate="Stopnja" +SndioInput="Vhodni zvočni odjemalec" + + diff --git a/plugins/sndio/data/locale/sv-SE.ini b/plugins/sndio/data/locale/sv-SE.ini new file mode 100644 index 0000000..cc3cc66 --- /dev/null +++ b/plugins/sndio/data/locale/sv-SE.ini @@ -0,0 +1,7 @@ +Channels="Antal kanaler" +Device="Enhet" +BitsPerSample="Bitar per sampling" +Rate="Hastighet" +SndioInput="Sndio-inmatningsklient" + + diff --git a/plugins/sndio/data/locale/tr-TR.ini b/plugins/sndio/data/locale/tr-TR.ini new file mode 100644 index 0000000..5ef2c22 --- /dev/null +++ b/plugins/sndio/data/locale/tr-TR.ini @@ -0,0 +1,7 @@ +Channels="Kanal sayısı" +Device="Aygıt" +BitsPerSample="Örnek başına bit" +Rate="Oran" +SndioInput="Sndio giriş istemcisi" + + diff --git a/plugins/sndio/data/locale/uk-UA.ini b/plugins/sndio/data/locale/uk-UA.ini new file mode 100644 index 0000000..a133916 --- /dev/null +++ b/plugins/sndio/data/locale/uk-UA.ini @@ -0,0 +1,7 @@ +Channels="Кількість каналів" +Device="Пристрій" +BitsPerSample="Біт на зразок" +Rate="Частота" +SndioInput="Клієнт введення Sndio" + + diff --git a/plugins/sndio/data/locale/zh-CN.ini b/plugins/sndio/data/locale/zh-CN.ini new file mode 100644 index 0000000..072ced5 --- /dev/null +++ b/plugins/sndio/data/locale/zh-CN.ini @@ -0,0 +1,7 @@ +Channels="通道数量" +Device="设备" +BitsPerSample="采样位数" +Rate="采样率" +SndioInput="Sndio 输入端" + + diff --git a/plugins/sndio/data/locale/zh-TW.ini b/plugins/sndio/data/locale/zh-TW.ini new file mode 100644 index 0000000..55710d7 --- /dev/null +++ b/plugins/sndio/data/locale/zh-TW.ini @@ -0,0 +1,7 @@ +Channels="聲道數目" +Device="裝置" +BitsPerSample="每樣本位元" +Rate="頻率" +SndioInput="Sndio 輸入裝置" + + diff --git a/plugins/sndio/sndio-input.c b/plugins/sndio/sndio-input.c new file mode 100644 index 0000000..d586e6a --- /dev/null +++ b/plugins/sndio/sndio-input.c @@ -0,0 +1,418 @@ +/* +Copyright (C) 2020 by Vadim Zhukov + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "sndio-input.h" + +#define blog(level, msg, ...) \ + blog(level, "sndio-input: %s: " msg, __func__, ##__VA_ARGS__); + +#define berr(level, msg, ...) \ + do { \ + const char *errstr = strerror(errno); \ + blog(level, msg ": %s", ##__VA_ARGS__, errstr); \ + } while (0) + +#define NSEC_PER_SEC 1000000000LL + +/** + * Returns the name of the plugin + */ +static const char *sndio_input_getname(void *unused) +{ + UNUSED_PARAMETER(unused); + return obs_module_text("SndioInput"); +} + +static enum speaker_layout sndio_channels_to_obs_speakers(int channels) +{ + switch (channels) { + case 1: + return SPEAKERS_MONO; + case 2: + return SPEAKERS_STEREO; + case 3: + return SPEAKERS_2POINT1; + case 4: + return SPEAKERS_4POINT0; + case 5: + return SPEAKERS_4POINT1; + case 6: + return SPEAKERS_5POINT1; + case 8: + return SPEAKERS_7POINT1; + } + return SPEAKERS_UNKNOWN; +} + +static enum audio_format sndio_to_obs_audio_format(const struct sio_par *par) +{ + switch (par->bits) { + case 8: + return AUDIO_FORMAT_U8BIT; + case 16: + return AUDIO_FORMAT_16BIT; + case 32: + return AUDIO_FORMAT_32BIT; + } + return AUDIO_FORMAT_UNKNOWN; +} + +/** + * Runs sndio tasks on a pre-opened audio device. + * Whenever user chooses another device, this thread gets signalled to exit, + * and another one starts immediately, without waiting for the previous. + */ +static void *sndio_thread(void *attr) +{ + struct sndio_thr_data *thrdata = attr; + size_t msgread = 0; // msg bytes read from socket + size_t nsiofds = sio_nfds(thrdata->hdl); + struct pollfd pfd[1 + nsiofds]; + struct sio_par par; + uint64_t ts; + ssize_t nread; + int pollres; + uint8_t *buf; + size_t bufsz; + + ts = os_gettime_ns(); + + bufsz = thrdata->par.appbufsz * thrdata->par.bps * 2; + if ((buf = bmalloc(bufsz * 2)) == NULL) { + blog(LOG_ERROR, "could not allocate record buffer of %zu bytes", + bufsz); + goto finish; + } + + memset(pfd, 0, sizeof(pfd)); + pfd[0].fd = thrdata->sock; + + for (;;) { + for (size_t i = 0; i <= nsiofds; i++) + pfd[i].revents = 0; + pfd[0].events = POLLIN; + sio_pollfd(thrdata->hdl, pfd + 1, POLLIN); + + if (poll(pfd, 1 + nsiofds, /*INFTIM*/ -1) == -1) { + if (errno == EINTR) + continue; + berr(LOG_ERROR, "exiting due to poll error"); + goto finish; + } + + if ((pfd[0].revents & POLLHUP) == POLLHUP) { + blog(LOG_INFO, + "exiting upon receiving EOF at IPC socket"); + goto finish; + } + if ((pfd[0].revents & POLLIN) == POLLIN) { + nread = read(pfd[0].fd, ((uint8_t *)&par) + msgread, + sizeof(par) - msgread); + switch (nread) { + case -1: + if (errno == EAGAIN) + goto proceed_sio; + berr(LOG_ERROR, + "reading from IPC socket failed"); + goto finish; + + case 0: + blog(LOG_INFO, + "exiting upon receiving EOF at IPC socket"); + goto finish; + + default: + msgread += (size_t)nread; + if (msgread == sizeof(struct sio_par)) { + size_t tbufsz; + uint8_t *tbuf; + + msgread = 0; + sio_stop(thrdata->hdl); + if (!sio_setpar(thrdata->hdl, &par)) { + blog(LOG_WARNING, + "sio_setpar failed, keeping old params"); + } + blog(LOG_INFO, + "after sio_setpar(): appbufsz=%u bps=%u", + par.appbufsz, par.bps); + memcpy(&thrdata->par, &par, + sizeof(struct sio_par)); + + tbufsz = thrdata->par.appbufsz * + thrdata->par.bps * 2; + if ((tbuf = brealloc(buf, tbufsz)) == + NULL) { + blog(LOG_ERROR, + "could not reallocate record buffer of %zu bytes", + tbufsz); + goto finish; + } + buf = tbuf; + bufsz = tbufsz; + + if (!sio_start(thrdata->hdl)) { + blog(LOG_ERROR, + "sio_start failed, exiting"); + goto finish; + } + ts = os_gettime_ns(); + // Since we restarted recording, + // do not try to handle events we lost. + continue; + } + } + } + + proceed_sio: + pollres = sio_revents(thrdata->hdl, pfd + 1); + if ((pollres & POLLHUP) == POLLHUP) { + blog(LOG_ERROR, "sndio device error happened, exiting"); + goto finish; + } + if ((pollres & POLLIN) == POLLIN) { + struct obs_source_audio out; + unsigned int nframes; + + nread = (ssize_t)sio_read(thrdata->hdl, buf, bufsz); + if (nread == 0) { + if (sio_eof(thrdata->hdl)) { + blog(LOG_ERROR, + "sndio device EOF happened, exiting"); + goto finish; + } + continue; + } + nframes = (unsigned int)nread / thrdata->par.bps; + //blog(LOG_INFO, "sio_read returned %u, nframes = %u", nread, nframes); + + memset(&out, 0, sizeof(struct obs_source_audio)); + out.data[0] = buf; + out.frames = nframes; + out.format = sndio_to_obs_audio_format(&thrdata->par); + out.speakers = sndio_channels_to_obs_speakers( + thrdata->par.rchan); + out.samples_per_sec = thrdata->par.rate; + out.timestamp = ts; + + ts += util_mul_div64(nframes, NSEC_PER_SEC, + thrdata->par.rate); + + obs_source_output_audio(thrdata->source, &out); + } + } + +finish: + sio_close(thrdata->hdl); + close(thrdata->sock); + bfree(buf); + bfree(thrdata); + return NULL; +} + +/** + * Destroy the plugin object and free all memory + */ +static void sndio_destroy(void *vptr) +{ + struct sndio_data *data = vptr; + + if (!data) + return; + close(data->sock); + data->sock = -1; + pthread_attr_destroy(&data->attr); + bfree(data); +} + +/** + * Tries to apply the input settings. + * Must be called on stopped device. + */ +static void sndio_apply(struct sndio_data *data, obs_data_t *settings) +{ + struct sndio_thr_data *thrdata; + pthread_t thread; + int ec; + int socks[2] = {-1, -1}; + const char *devname = obs_data_get_string(settings, "device"); + + if ((thrdata = bzalloc(sizeof(struct sndio_thr_data))) == NULL) { + blog(LOG_ERROR, "malloc"); + return; + } + if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0, + socks) == -1) { + berr(LOG_ERROR, "socketpair"); + goto error; + } + + if (data->sock != -1) + close(data->sock); + data->sock = socks[0]; + thrdata->sock = socks[1]; + thrdata->source = data->source; + + thrdata->hdl = sio_open(devname, SIO_REC, 0); + if (!thrdata->hdl) { + berr(LOG_ERROR, "could not open %s sndio device", devname); + goto error; + } + + sio_initpar(&thrdata->par); + thrdata->par.bits = obs_data_get_int(settings, "bits"); + thrdata->par.bps = SIO_BPS(thrdata->par.bits); + thrdata->par.sig = thrdata->par.bits > 8; + thrdata->par.le = 1; + thrdata->par.rate = obs_data_get_int(settings, "rate"); + thrdata->par.rchan = obs_data_get_int(settings, "channels"); + thrdata->par.xrun = SIO_SYNC; // makes timestamping easy + if (!sio_setpar(thrdata->hdl, &thrdata->par)) { + berr(LOG_ERROR, "could not set parameters for %s sndio device", + devname); + goto error; + } + blog(LOG_INFO, "after initial sio_setpar(): appbufsz=%u bps=%u", + thrdata->par.appbufsz, thrdata->par.bps); + + if (!sio_start(thrdata->hdl)) { + berr(LOG_ERROR, "could not start recording on %s sndio device", + devname); + goto error; + } + + ec = pthread_create(&thread, &data->attr, sndio_thread, thrdata); + if (ec != 0) { + blog(LOG_ERROR, "could not start thread"); + goto error; + } + + return; + +error: + if (thrdata->hdl != NULL) + sio_close(thrdata->hdl); + close(socks[0]); + close(socks[1]); + bfree(thrdata); +} + +/** + * Update the input settings. + */ +static void sndio_update(void *vptr, obs_data_t *settings) +{ + struct sndio_data *data = vptr; + sndio_apply(data, settings); +} + +/** + * Create the plugin object + */ +static void *sndio_create(obs_data_t *settings, obs_source_t *source) +{ + struct sndio_data *data = bzalloc(sizeof(struct sndio_data)); + pthread_attr_init(&data->attr); + pthread_attr_setdetachstate(&data->attr, PTHREAD_CREATE_DETACHED); + data->source = source; + data->sock = -1; + sndio_apply(data, settings); + return data; +} + +/** + * Get plugin defaults + */ +static void sndio_input_defaults(obs_data_t *settings) +{ + obs_data_set_default_string(settings, "device", SIO_DEVANY); + obs_data_set_default_int(settings, "rate", 48000); + obs_data_set_default_int(settings, "bits", 16); + obs_data_set_default_int(settings, "channels", 2); +} + +/** + * Get plugin properties + */ +static obs_properties_t *sndio_input_properties(void *unused) +{ + obs_property_t *rate, *bits; + + UNUSED_PARAMETER(unused); + + obs_properties_t *props = obs_properties_create(); + + obs_properties_add_text(props, "device", obs_module_text("Device"), + OBS_TEXT_DEFAULT); + + rate = obs_properties_add_list(props, "rate", obs_module_text("Rate"), + OBS_COMBO_TYPE_LIST, + OBS_COMBO_FORMAT_INT); + obs_property_list_add_int(rate, "11025 Hz", 11025); + obs_property_list_add_int(rate, "22050 Hz", 22050); + 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); + obs_property_list_add_int(rate, "96000 Hz", 96000); + obs_property_list_add_int(rate, "192000 Hz", 192000); + + bits = obs_properties_add_list(props, "bits", + obs_module_text("BitsPerSample"), + OBS_COMBO_TYPE_LIST, + OBS_COMBO_FORMAT_INT); + obs_property_list_add_int(bits, "8", 8); + obs_property_list_add_int(bits, "16", 16); + obs_property_list_add_int(bits, "32", 32); + + obs_properties_add_int(props, "channels", obs_module_text("Channels"), + 1, 8, 1); + + return props; +} + +struct obs_source_info sndio_output_capture = { + .id = "sndio_output_capture", + .type = OBS_SOURCE_TYPE_INPUT, + .output_flags = OBS_SOURCE_AUDIO, + .get_name = sndio_input_getname, + .create = sndio_create, + .destroy = sndio_destroy, +#if SHUTDOWN_ON_DEACTIVATE + .activate = sndio_activate, + .deactivate = sndio_deactivate, +#endif + .update = sndio_update, + .get_defaults = sndio_input_defaults, + .get_properties = sndio_input_properties, + .icon_type = OBS_ICON_TYPE_AUDIO_OUTPUT, +}; diff --git a/plugins/sndio/sndio-input.h b/plugins/sndio/sndio-input.h new file mode 100644 index 0000000..0fa286b --- /dev/null +++ b/plugins/sndio/sndio-input.h @@ -0,0 +1,18 @@ +#ifndef OBS_SNDIO_INPUT_H +#define OBS_SNDIO_INPUT_H + +struct sndio_thr_data { + obs_source_t *source; + struct obs_source_audio out; + struct sio_hdl *hdl; + struct sio_par par; + int sock; +}; + +struct sndio_data { + obs_source_t *source; + pthread_attr_t attr; + int sock; +}; + +#endif // OBS_SNDIO_INPUT_H diff --git a/plugins/sndio/sndio.c b/plugins/sndio/sndio.c new file mode 100644 index 0000000..5e1c0ba --- /dev/null +++ b/plugins/sndio/sndio.c @@ -0,0 +1,32 @@ +/* +Copyright (C) 2020 by Vadim Zhukov + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ +#include + +OBS_DECLARE_MODULE() +OBS_MODULE_USE_DEFAULT_LOCALE("sndio", "en-US") +MODULE_EXPORT const char *obs_module_description(void) +{ + return "sndio output capture"; +} + +extern struct obs_source_info sndio_output_capture; + +bool obs_module_load(void) +{ + obs_register_source(&sndio_output_capture); + return true; +} diff --git a/plugins/text-freetype2/CMakeLists.txt b/plugins/text-freetype2/CMakeLists.txt index 5b4e1e5..c561d44 100644 --- a/plugins/text-freetype2/CMakeLists.txt +++ b/plugins/text-freetype2/CMakeLists.txt @@ -42,9 +42,6 @@ elseif(APPLE) set(text-freetype2_PLATFORM_DEPS ${COCOA} ${ICONV_LIBRARIES}) - - set_source_files_properties(find-font-cocoa.m - PROPERTIES LANGUAGE C) else() find_package(Fontconfig QUIET) if(NOT FONTCONFIG_FOUND AND ENABLE_FREETYPE) diff --git a/plugins/text-freetype2/data/locale/ar-SA.ini b/plugins/text-freetype2/data/locale/ar-SA.ini index b9f3f5c..3bfed08 100644 --- a/plugins/text-freetype2/data/locale/ar-SA.ini +++ b/plugins/text-freetype2/data/locale/ar-SA.ini @@ -3,6 +3,8 @@ Font="الخط" Text="النص" TextFile="ملف نص (UTF-8 أو UTF-16)" TextFileFilter="ملفات نصية (*.txt);;" +ChatLogMode="وضع سجل الدردشة" +ChatLogLines="خطوط سجل الدردشة" Color1="اللون الأول" Color2="اللون الثاني" Outline="حدود" diff --git a/plugins/text-freetype2/data/locale/de-DE.ini b/plugins/text-freetype2/data/locale/de-DE.ini index 4c65d37..e6c8d4c 100644 --- a/plugins/text-freetype2/data/locale/de-DE.ini +++ b/plugins/text-freetype2/data/locale/de-DE.ini @@ -1,7 +1,7 @@ TextFreetype2="Text (FreeType 2)" Font="Schriftart" Text="Text" -TextFile="Textdatei (UTF‐8 oder UTF‐16)" +TextFile="Textdatei (UTF-8 oder UTF-16)" TextFileFilter="Textdateien (*.txt);;" ChatLogMode="Chatlogmodus" ChatLogLines="Chatlogzeilen" diff --git a/plugins/text-freetype2/data/locale/el-GR.ini b/plugins/text-freetype2/data/locale/el-GR.ini index 3a4e7b8..871031a 100644 --- a/plugins/text-freetype2/data/locale/el-GR.ini +++ b/plugins/text-freetype2/data/locale/el-GR.ini @@ -10,4 +10,5 @@ DropShadow="Προσπίπτουσα Σκιά" ReadFromFile="Ανάγνωση από αρχείο" CustomWidth="Προσαρμοσμένο πλάτος κειμένου" WordWrap="Αναδίπλωση Λέξεων" +Antialiasing="Ενεργοποίηση Εξομάλυνσης" diff --git a/plugins/text-freetype2/data/locale/fa-IR.ini b/plugins/text-freetype2/data/locale/fa-IR.ini index 9b25f9f..32bc6b8 100644 --- a/plugins/text-freetype2/data/locale/fa-IR.ini +++ b/plugins/text-freetype2/data/locale/fa-IR.ini @@ -12,4 +12,5 @@ DropShadow="افتادن سایه" ReadFromFile="از فایل بخوان" CustomWidth="رنگ متن سفارشی" WordWrap="بسته بندی کلمات" +Antialiasing="فعال کردن ضد لبه" diff --git a/plugins/text-freetype2/data/locale/kab-KAB.ini b/plugins/text-freetype2/data/locale/kab-KAB.ini new file mode 100644 index 0000000..56b4970 --- /dev/null +++ b/plugins/text-freetype2/data/locale/kab-KAB.ini @@ -0,0 +1,16 @@ +TextFreetype2="Aḍris (FreeType 2)" +Font="Tasefsit" +Text="Aḍris" +TextFile="Afaylu aḍris (UTF-8 neɣ UTF-16)" +TextFileFilter="Ifuyla iḍrisen (*.txt);;" +ChatLogMode="Askar n uɣmis n umeslay" +ChatLogLines="Ijerriḍen n uɣmis n umeslay" +Color1="Ini 1" +Color2="Ini 2" +Outline="Azizdew" +DropShadow="Tili" +ReadFromFile="Ɣer-d seg ufaylu" +CustomWidth="Tehri n uḍris yugnen" +WordWrap="Tuɣalin tawurmant s ajerriḍ" +Antialiasing="Sermed amzay" + diff --git a/plugins/text-freetype2/data/locale/pt-BR.ini b/plugins/text-freetype2/data/locale/pt-BR.ini index aa415c6..5867da6 100644 --- a/plugins/text-freetype2/data/locale/pt-BR.ini +++ b/plugins/text-freetype2/data/locale/pt-BR.ini @@ -1,16 +1,16 @@ TextFreetype2="Texto (FreeType 2)" Font="Fonte" Text="Texto" -TextFile="Arquivo de Texto (UTF-8 ou UTF-16)" +TextFile="Arquivo de texto (UTF-8 ou UTF-16)" TextFileFilter="Arquivos de texto (*.txt);;" -ChatLogMode="Modo de Bate-Papo" -ChatLogLines="Linhas de Bate-Papo" +ChatLogMode="Modo de chat" +ChatLogLines="Linhas do chat" Color1="Cor 1" Color2="Cor 2" Outline="Contorno" DropShadow="Sombra" ReadFromFile="Ler de arquivo" CustomWidth="Largura do texto personalizada" -WordWrap="Quebra de Linha" -Antialiasing="Ativar Anti-Aliasing" +WordWrap="Quebra de linha" +Antialiasing="Ativar anti-aliasing" diff --git a/plugins/text-freetype2/data/locale/ro-RO.ini b/plugins/text-freetype2/data/locale/ro-RO.ini index cdee2c0..5b53e80 100644 --- a/plugins/text-freetype2/data/locale/ro-RO.ini +++ b/plugins/text-freetype2/data/locale/ro-RO.ini @@ -3,8 +3,8 @@ Font="Font" Text="Text" TextFile="Fișier text (UTF-8 sau UTF-16)" TextFileFilter="Fișiere text (*.txt);;" -ChatLogMode="Mod jurnal chat" -ChatLogLines="Linii jurnal chat" +ChatLogMode="Mod pentru jurnal de chat" +ChatLogLines="Linii pentru jurnal de chat" Color1="Culoarea 1" Color2="Culoarea 2" Outline="Contur" @@ -12,5 +12,5 @@ DropShadow="Umbrire" ReadFromFile="Citește din fișier" CustomWidth="Lățime de text personalizată" WordWrap="Încadrare pentru cuvinte" -Antialiasing="Activează antialiasing" +Antialiasing="Activează antialiasingul" diff --git a/plugins/vlc-video/data/locale/de-DE.ini b/plugins/vlc-video/data/locale/de-DE.ini index 7d3ec17..cb63a2d 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‐Videoquelle" +VLCSource="VLC-Videoquelle" Playlist="Playlist" LoopPlaylist="Playlist wiederholen" Shuffle="Playlist zufällig wiedergeben" diff --git a/plugins/vlc-video/data/locale/el-GR.ini b/plugins/vlc-video/data/locale/el-GR.ini index 1bff90e..5d337ca 100644 --- a/plugins/vlc-video/data/locale/el-GR.ini +++ b/plugins/vlc-video/data/locale/el-GR.ini @@ -12,4 +12,7 @@ Restart="Επανεκκίνηση" Stop="Διακοπή" PlaylistNext="Επόμενο" PlaylistPrev="Προηγούμενο" +AudioTrack="Κομμάτι Ήχου" +SubtitleTrack="Κομμάτι Υποτίτλων" +SubtitleEnable="Ενεργοποίηση Υποτίτλων" diff --git a/plugins/vlc-video/data/locale/et-EE.ini b/plugins/vlc-video/data/locale/et-EE.ini index 6b419b8..bd3d67f 100644 --- a/plugins/vlc-video/data/locale/et-EE.ini +++ b/plugins/vlc-video/data/locale/et-EE.ini @@ -1,8 +1,15 @@ VLCSource="VLC Video allikas" Playlist="Esitusloend" LoopPlaylist="Korda esitusloendit" +Shuffle="Juhuesita esitlusloend" PlaybackBehavior="Käitumine" PlaybackBehavior.StopRestart="Lõpeta kui nähtamatu, alusta uuesti kui nähtav" PlaybackBehavior.PauseUnpause="Peata kui nähtamatu, jätka kui nähtav" PlaybackBehavior.AlwaysPlay="Mängi alati, isegi siis kui pole nähtav" +PlayPause="Esita/Peata" +Restart="Taaskäivita" +Stop="Lõpeta" +PlaylistNext="Edasi" +PlaylistPrev="Eelmine" +AudioTrack="Helirada" diff --git a/plugins/vlc-video/data/locale/fa-IR.ini b/plugins/vlc-video/data/locale/fa-IR.ini index 3a98f47..58ca734 100644 --- a/plugins/vlc-video/data/locale/fa-IR.ini +++ b/plugins/vlc-video/data/locale/fa-IR.ini @@ -5,10 +5,14 @@ Shuffle="پخش درهم" PlaybackBehavior="کنش های دیداری" PlaybackBehavior.StopRestart="توقف زمانی که قابل مشاهده نیست، راه اندازی مجدد زمانی که قابل مشاهده است" PlaybackBehavior.PauseUnpause="توقف زمانی که قابل مشاهده نیست، راه اندازی مجدد زمانی که قابل مشاهده است" +PlaybackBehavior.AlwaysPlay="همیشه حتی وقتی دیده نمی شود اجرا کنید" NetworkCaching="ذخیره سازی اینترنت (ms)" PlayPause="پخش/توقف" Restart="راه اندازی مجدد" Stop="توقف" PlaylistNext="بعدی" PlaylistPrev="قبلی" +AudioTrack="قطعه صدا" +SubtitleTrack="قطعه زیرنویس" +SubtitleEnable="زیرنویس فعال" diff --git a/plugins/vlc-video/data/locale/fil-PH.ini b/plugins/vlc-video/data/locale/fil-PH.ini index 1f48289..a19b893 100644 --- a/plugins/vlc-video/data/locale/fil-PH.ini +++ b/plugins/vlc-video/data/locale/fil-PH.ini @@ -12,4 +12,5 @@ Restart="Ulitin" Stop="Itigil" PlaylistNext="Susunod" PlaylistPrev="Nakaraan" +AudioTrack="Track ng Dami" diff --git a/plugins/vlc-video/data/locale/kab-KAB.ini b/plugins/vlc-video/data/locale/kab-KAB.ini new file mode 100644 index 0000000..bd1e822 --- /dev/null +++ b/plugins/vlc-video/data/locale/kab-KAB.ini @@ -0,0 +1,18 @@ +VLCSource="Aɣbalu n uvidyu VLC" +Playlist="Tabdart n tɣuri" +LoopPlaylist="Ales tabdart n tɣuri" +Shuffle="Taɣuri tagacurant" +PlaybackBehavior="Tikli n twalit" +PlaybackBehavior.StopRestart="Ḥbes ticki ur yettban ara, ales asekker ticki yettban" +PlaybackBehavior.PauseUnpause="Bedd ticki ur yettban ara, kemmel ticki yettban" +PlaybackBehavior.AlwaysPlay="Ad itteddu yalas ɣas ma ur yettban ara" +NetworkCaching="Tuffirt n uzeḍḍa (ms)" +PlayPause="Ɣer/Bedd" +Restart="Ales asekker" +Stop="Seḥbes" +PlaylistNext="Win ɣers" +PlaylistPrev="Ɣer deffir" +AudioTrack="Tazribt n umeslaw" +SubtitleTrack="Tazribt n iduzwilen" +SubtitleEnable="Iduzwilen remden" + diff --git a/plugins/vlc-video/data/locale/pt-BR.ini b/plugins/vlc-video/data/locale/pt-BR.ini index 23f0d0c..f04871d 100644 --- a/plugins/vlc-video/data/locale/pt-BR.ini +++ b/plugins/vlc-video/data/locale/pt-BR.ini @@ -1,12 +1,12 @@ VLCSource="Fonte de vídeo do VLC" Playlist="Lista de reprodução" -LoopPlaylist="Repetir a Lista de reprodução" -Shuffle="Misturar a Lista" +LoopPlaylist="Reproduzir em loop" +Shuffle="Reproduzir aleatoriamente" 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="Sempre reproduzir, mesmo quando não visível" -NetworkCaching="Cache de Rede (ms)" +NetworkCaching="Cache de rede (ms)" PlayPause="Reproduzir/Pausar" Restart="Reiniciar" Stop="Parar" diff --git a/plugins/vlc-video/data/locale/ro-RO.ini b/plugins/vlc-video/data/locale/ro-RO.ini index 9902459..9454bc0 100644 --- a/plugins/vlc-video/data/locale/ro-RO.ini +++ b/plugins/vlc-video/data/locale/ro-RO.ini @@ -1,10 +1,10 @@ VLCSource="Sursă video VLC" -Playlist="Listă de redare" -LoopPlaylist="Repetă lista de redare" -Shuffle="Amestecă lista de redare" +Playlist="Playlist" +LoopPlaylist="Repetă playlistul" +Shuffle="Amestecă playlistul" PlaybackBehavior="Comportamentul vizibilității" PlaybackBehavior.StopRestart="Oprește când sursa nu este vizibilă, repornește când este vizibilă" -PlaybackBehavior.PauseUnpause="Pune pe pauză când sursa nu este vizibilă, scoate de pe pauză când este vizibilă" +PlaybackBehavior.PauseUnpause="Pune pe pauză când sursa nu e vizibilă, scoate de pe pauză când e vizibilă" PlaybackBehavior.AlwaysPlay="Redă întotdeauna chiar și atunci când sursa nu este vizibilă" NetworkCaching="Caching de rețea (ms)" PlayPause="Redă/Pune pe pauză" @@ -13,6 +13,6 @@ Stop="Oprește" PlaylistNext="Următorul" PlaylistPrev="Anteriorul" AudioTrack="Pistă audio" -SubtitleTrack="Pistă subtitrare" +SubtitleTrack="Pistă de subtitrare" SubtitleEnable="Subtitrări activate" diff --git a/plugins/vlc-video/vlc-video-source.c b/plugins/vlc-video/vlc-video-source.c index fe9eabf..dce6d47 100644 --- a/plugins/vlc-video/vlc-video-source.c +++ b/plugins/vlc-video/vlc-video-source.c @@ -332,6 +332,8 @@ static void vlcs_get_metadata(void *data, calldata_t *cd) VLC_META(media, cd, data_id, "album_artist", libvlc_meta_AlbumArtist) VLC_META(media, cd, data_id, "disc_number", libvlc_meta_DiscNumber) VLC_META(media, cd, data_id, "disc_total", libvlc_meta_DiscTotal) + + libvlc_media_release_(media); #undef VLC_META } @@ -554,7 +556,7 @@ static bool valid_extension(const char *ext) else dstr_copy(&test, b); - if (dstr_cmp(&test, ext) == 0) { + if (dstr_cmpi(&test, ext) == 0) { valid = true; break; } diff --git a/test/cmocka/CMakeLists.txt b/test/cmocka/CMakeLists.txt index 747d432..e1a5bb7 100644 --- a/test/cmocka/CMakeLists.txt +++ b/test/cmocka/CMakeLists.txt @@ -37,3 +37,10 @@ target_link_libraries(test_darray ${CMOCKA_LIBRARIES} libobs) add_test(test_darray ${CMAKE_CURRENT_BINARY_DIR}/test_darray) fixLink(test_darray) + +# bitstream test +add_executable(test_bitstream test_bitstream.c) +target_link_libraries(test_bitstream ${CMOCKA_LIBRARIES} libobs) + +add_test(test_bitstream ${CMAKE_CURRENT_BINARY_DIR}/test_bitstream) +fixLink(test_bitstream) diff --git a/test/cmocka/test_bitstream.c b/test/cmocka/test_bitstream.c new file mode 100644 index 0000000..8bc0262 --- /dev/null +++ b/test/cmocka/test_bitstream.c @@ -0,0 +1,34 @@ +#include +#include +#include +#include + +#include + +static void bitstream_test(void **state) +{ + struct bitstream_reader reader; + uint8_t data[6] = {0x34, 0xff, 0xe1, 0x23, 0x91, 0x45}; + + // set len to one less than the array to show that we stop reading at that len + bitstream_reader_init(&reader, data, 5); + + assert_int_equal(bitstream_reader_read_bits(&reader, 8), 0x34); + assert_int_equal(bitstream_reader_read_bits(&reader, 1), 1); + assert_int_equal(bitstream_reader_read_bits(&reader, 3), 7); + assert_int_equal(bitstream_reader_read_bits(&reader, 4), 0xF); + assert_int_equal(bitstream_reader_r8(&reader), 0xe1); + assert_int_equal(bitstream_reader_r16(&reader), 0x2391); + + // test reached end + assert_int_equal(bitstream_reader_r8(&reader), 0); +} + +int main() +{ + const struct CMUnitTest tests[] = { + cmocka_unit_test(bitstream_test), + }; + + return cmocka_run_group_tests(tests, NULL, NULL); +} diff --git a/test/cmocka/test_serializer.c b/test/cmocka/test_serializer.c index 9c41d2e..c6f426f 100644 --- a/test/cmocka/test_serializer.c +++ b/test/cmocka/test_serializer.c @@ -7,6 +7,7 @@ static void serialize_test(void **state) { + UNUSED_PARAMETER(state); struct array_output_data output; struct serializer s;