Projects
home:frispete
obs-studio
Sign Up
Log In
Username
Password
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
Expand all
Collapse all
Changes of Revision 9
View file
obs-studio.changes
Changed
@@ -1,4 +1,271 @@ ------------------------------------------------------------------- +Sun Jan 08 14:16:44 UTC 2023 - hpj@urpla.net + +- Update to version 29.0.0: + * rtmp-services: Specify RTMP_SERVICES_FORMAT_VERSION in package.json + * CI: Revise repository conditions to validate JSON schema of services + * libobs: Update version to 29.0.0 + * win-capture: Always reset timeout when searching for target display + * UI: Lock volume meter sliders to LTR + * UI: Use stream encoder when resetting encoders + * obs-filters: Log NVIDIA Effects version only if lib is found + * CI: Use Flatpak build-bundle option + * CI: Update Flatpak Actions + * Revert "libobs-d3d11: Default to Intel IGPU on IGPU+DGPU systems" + * Revert "libobs-d3d11: Make sure libobs knows the new adapter index" + * Revert "libobs: Fix adapter index not getting applied to resets" + * UI: Restrict GNOME wayland override + * obs-ffmpeg, obs-qsv11: Ensure adapter order in encoder tests + * obs-ffmpeg: Remove EnumOutputs from encoder tests + * libobs: Add funcs to get windows video adapter LUIDs + * rtmp-services: Remove defunct servers/services + * obs-ffmpeg: Set chroma location for VA-API + * obs-qsv11: Put mastering primaries in GBR order + * mac-videotoolbox: Add HDR metadata + * obs-ffmpeg: Fix AMF default CQP value + * libobs: Duplicate URL string for OBS_BUTTON_URL + * UI: Fix Qt AutoUic warning + * obs-ffmpeg: Add new rate control method mappings for AVC/HEVC + * obs-filter: Fix upward compressor + * obs-ffmpeg: Use enum for av1 encoders + * cmake: Fix FindGio.cmake to find libgio + * docs: Add missing source functions + * obs-ffmpeg: Bump AMF version to v1.4.29 + * obs-ffmpeg: Add new rate control methods for AMD AVC/HEVC + * docs: Fix reference count info of obs_frontend_get_streaming_service + * libcaption: Fix invalid data at utf8_load_text_file + * docs: Add versionadded for 29.0.0 functions + * docs: Add info on property modified callback + * mac-videotoolbox: Don't parse HEVC as AVC + * UI: Guard GetMonitorName behind Qt < 6.4 + * UI: Fix slide counter with no slides + * obs-ffmpeg: Improve chroma location decision + * docs: Clarify signal_handler_connect() + * obs-filters: Use correct signal to reset greenscreen filter + * image-source: Remove cleared missing files from slideshow + * libobs: Override fps ovi for aux views + * updater: Bump to version 2.2 + * obs-ffmpeg: Allow srt stream to disconnect after timeout + * rtmp-services: Add Bitmovin + * obs-qsv11: Set subprocess timeout to 10 sec + * win-dshow: Ignore FFmpeg colorspace if overridden + * obs-ffmpeg: Disable VBAQ for H264 CQP rate control + * obs-qsv11: Fix QSV detection + * obs-qsv11: Fix encoder capping resolution on dgpus + * Revert "obs-qsv11: Don't set to low power mode if AV1" + * obs-qsv11: Fix HDR not working with AV1 + * obs-qsv11: Don't set to low power mode if AV1 + * obs-qsv11: Keep ExtParam value around + * UI: Hide "Update Channel" label on macOS + * UI: Guard AutoBetaOptIn as Windows-only + * UI: Delay timed update check until branch migration + * UI: Fix monitor name for projectors on Windows + * obs-qsv11: Remove statics, fix buffer misuse + * obs-qsv11: Add HEVC + * obs-qsv11: Don't declare vars in switch w/o braces + * obs-qsv11: Remove unused function + * obs-qsv11: Fix profile default for AV1 + * obs-qsv11: Remove unused function declaration + * obs-ffmpeg: Disable VBAQ for HEVC CQP rate control + * libobs: Suppress LNK4098 + * rtmp-services: Suppress LNK4098 + * UI: Add QSV AV1 to simple output mode + * obs-qsv11: Simplify CQP + * obs-qsv11: Add QSV AV1 encoder + * obs-qsv11: Add codec enum + * obs-qsv11: Only reinitialize bitrate + * obs-qsv11: Add startup process to test QSV support + * libobs: Fix adapter index not getting applied to resets + * UI: Switch to beta branch when running beta/rc for the first time + * UI: Add update channels (Windows) + * updater: Add --branch/--portable command line arguments + * cmake/libobs: Set OBS_COMMIT based on git describe + * flatpak: Update deps based on obs-deps 2022-11-21 + * CI: Update deps to obs-deps 2022-11-21 release + * libobs-d3d11: Make sure libobs knows the new adapter index + * obs-ffmpeg: Fix building without HEVC on Windows + * cmake: Specify utf-8 for MSVC builds + * CI,obs-vst: Update Flatpak KDE Runtime to version 6.4 + * UI, image-source: Add slide counter to slideshow toolbar + * obs-vst: Improve some string handling + * obs-vst: Use libobs memory allocation functions + * UI: Disable toolbar buttons when no source is selected + * obs-ffmpeg: Improve RIST/SRT log messages + * UI: Use blog for "Attempted path" log messages + * ffmpeg: fix cqp rate control on svtav1 + * ffmpeg: fix "cqp" mode for libaom + * libobs: Deprecate obs_get/set_master_volume + * obs-browser: Don't use QPointF for pointer position + * obs-browser: Update version to 2.19.0 + * libdshowcapture: Support more capture cards with uncoupled audio + * obs-ffmpeg: Use Libva in FFmpeg VA-API + * UI: Add filters button to scenes toolbar + * UI: Remove Qt taskbar overlay + * obs-ffmpeg: Fix SVT-AV1 rate control mode selection + * libobs: Allow overriding video resolution per view + * decklink: Always output BGRA + * UI: Clarify that RGB output format is BGRA + * flatpak: Add Jansson to modules + * mac-videotoolbox: Default to High profile + * UI: Add Apple Hardware Encoder to AutoConfig + * win-dshow: Recognise higher FPS values from devices + * CI: Name Docs zip based on commit/tag + * obs-ffmpeg: Fix encoder preset quality fallbacks for AVC/HEVC/AV1 + * obs-ffmpeg: Suggest docs to reference for AMF/FFmpeg options + * UI: Add AMD AV1 to simple output mode + * obs-ffmpeg: Add AMF AV1 encoder + * obs-ffmpeg: Use codec enum for AMF texture encode check + * obs-ffmpeg: Make AMF AVC encoder name consistent w/ others + * obs-ffmpeg: Only show b-frames AMF property for AVC + * obs-ffmpeg: Only allow AMF high/baseline profiles for AVC + * obs-ffmpeg: Allow 0-51 for CQP property + * obs-ffmpeg: Use codec enum for amf_properties_internal + * obs-ffmpeg: Fix transcoding API typo + * obs-ffmpeg: Update AMF SDK for AV1 support + * UI: Change Simple Output NVENC default preset to P5 + * CI: Re-enable scripting in Windows builds + * obs-ffmpeg: Change default nvenc preset to P5 + * win-capture,UI: Look up display by id, not index + * Revert "virtualcam-module: Don't send frames on initial pause" + * obs-websocket: Update version to 5.1.0 + * obs-ffmpeg: Fix SRT error type comparison (#7802) + * win-capture: Invert output when drawing monochrome cursors + * rtmp-services: Add ffmpeg-mpegts-muxer in schema v4 + * obs-ffmpeg: Direct setting of encryption & auth for SRT & RIST + * UI: Use weak source for projectors + * obs-ffmpeg: Use compatibility options on nvnenc init fail + * libobs: Fix SRGB to SCRGB async video rendering + * CI: Fix building in PowerShell 7.3.x + * CI: Fix services checkers using wrong port for RTMPS + * UI: Add separator in source toolbar + * obs-outputs: Shorten dynamic bitrate increment timeout + * rtmp-services: Add IRLToolkit + * UI: Remove number from multiview labels + * CI: Add debian debug symbols to CI artifacts + * cmake: Fix debian packages loosing all debug symbols + * mac-capture: Disable all SCK modes besides WindowCapture on macOS 12 + * mac-videotoolbox: Support P010 and HDR color spaces + * obs-filters: NVIDIA Background Removal variable mask refresh + * obs-filters: Add temporal processing to Background Removal + * obs-filters: Warn if NVIDIA Audio FX is outdated + * obs-filters: Warn if NVIDIA Video FX is oudated + * obs-outputs: Increase librtmp send timeout to 15 seconds + * UI: Fix snprintf calls with literals as buffer sizes + * obs-outputs: Fix snprintf calls with literals as buffer sizes + * obs-filters: Fix snprintf calls with literals as buffer sizes + * image-source: Fix snprintf calls with literals as buffer sizes + * coreaudio-encoder: Fix snprintf calls with literals as buffer sizes + * obs-x264: Fix snprintf calls with literals as buffer sizes + * win-capture: Replace invocations of sprintf with snprintf + * obs-ffmpeg: Replace invocations of sprintf with snprintf + * libobs-d3d11: Replace invocations of sprintf with snprintf + * linux-v4l2: Replace invocations of sprintf with snprintf + * linux-capture: Replace invocations of sprintf with snprintf + * UI: Replace invocations of sprintf with snprintf + * obs-outputs: Replace invocations of sprintf with snprintf + * mac-capture: Replace invocations of sprintf with snprintf + * libobs: Replace invocations of sprintf with snprintf + * deps: Replace invocations of sprintf with snprintf + * obs-ffmpeg: Fix deprecation of channels member of several structs + * libobs: Change audio resampler to new channel API + * obs-ffmpeg: Update mpegts to channel API change + * docs: Add info on funcs to use for properties + * aja: Fix capturing UHD/4K YUV on Kona HDMI. + * UI: Fix QStyle memory leak + * libobs-d3d11: Support advanced SDR window preview + * mac-capture: Support P3 for HDR recordings + * libobs: Add P3 shaders for Mac + * libobs-opengl: Support l10r IOSurface + * decklink-output-ui: Pipeline GPU data for preview + * libobs: Log Windows emulation status + * libobs: Log macOS Rosetta status + * UI: Remove Rosetta detection log + * libobs/util: Add function to get Windows x64 emulation status + * UI: Use on_foo_bar properly for docks context menu + * UI: Replace manual usage of on_foo_bar for show/hide transition + * UI: Remove support for toggling Aero + * libobs: Remove Aero logging + * mac-avcapture: Add DeskCam support + * rtmp-services: Add Whowatch + * libobs: Fix reading Windows release name + * UI: Set Replay Buffer Memory limit dynamically + * libobs: Add utility function to get total RAM + * libobs: Move async filtering from render to tick + * libobs: Add "source_update" signal + * docs: Add clarifications + * UI: Fix always on top not being saved on exit + * libobs: Update to 28.1.2 + * CI: Upload beta builds as Steam Playtest + * obs-filters: Add a simple 3-band equalizer + * obs-browser: Update version to 2.18.7 + * UI: Add simple mode for Apple Hardware HEVC + * UI: Add detection of ProRes encoder for auto muxing + * UI: Print container warnings for ProRes encoder and disable autoremux + * libobs: Force hvc1 codec tag for HEVC video and respect input tags + * mac-videtoolbox: Use correct size for system representation CFStrings + * mac-videotoolbox: Make unsupported color format text codec agnostic + * mac-videotoolbox: Remove HW_ACCEL flags + * mac-videotoolbox: Add support platform hardware and software ProRes 422 + * obs-ffmpeg: Add codec-tag support to ffmpeg-mux + * mac-videotoolbox: Add support for platform hardware and software HEVC + * Revert "obs-ffmpeg: Check nvenc max bframe count" + * obs-ffmpeg: Cap NVENC Max B-frames according to GPU caps + * CI: Fix service validator + * libobs: Update version to 28.1.1 + * obs-ffmpeg: Check nvenc max bframe count + * UI: Migrate Simple Output NVENC preset + * UI: Refactor NVENC preset migration + * libobs: Update version to 28.1.0 + * libobs: Force SRGB conversion for tonemapped video + * obs-ffmpeg: Split NVENC preset migrations by codec + * UI: Add NVENC preset migration for lossless + * obs-ffmpeg: Align NVENC preset migrations to NVIDIA guidelines + * obs-ffmpeg: Add NVENC preset mapping for old Default preset + * obs-ffmpeg: Swap hq and mq preset order + * UI: Change adv audio background color + * UI/obs-frontend-api: Return allocated strings for new funcs + * obs-frontend-api: Add functions to get last saved files + * libobs: Fix blend method in studio mode + * libobs: Add media key support for linux + * win-capture: Disable clang-format for assembly patterns + * obs-filters: Fix typo in Upward.Compressor + * obs-ffmpeg: Fix Ubuntu 20.04 detection + * obs-ffmpeg: Fix FFmpeg NVENC presets on Ubuntu 20.04 + * obs-filters: Fix comment typo + * obs-filters: Add upward compressor filter + * obs-filters: Refactor expander filter expansion code + * obs-filters: Use snake_case for expander variables + * Update translations from Crowdin + * obs-browser: Update version to 2.18.6 + * enc-amf: Minor compilation improvements + * UI: Use correct key for "Always on Top" with projectors + * rtmp-services: Add Vindral service + * UI: Fix placeholder element not being deleted + * UI: Avoid showing service integration page on Wayland + * obs-frontend-api: Add screenshot event + * UI: Set preset2 instead preset for simple mode NVENC + * UI: Hide --portable from help text if disallowed + * UI: Hide donation CTA when running via Steam + * UI: Add --steam flag + * linux-v4l2: Send STREAMON/STREAMOFF on vcam start/stop + * docs: Fix sphinx import error on Python 3.10+ + * obs-ffmpeg: Fix NVENC "mq" to use P6 rather than P4 + * UI: Change "hq" to use P5 when upgrading NVENC + * UI: Fix stats widget appearance on Yami themes + * UI: Fix stats widget status font size + * UI: Fix theme if apply and cancel in settings + * CI: Fix Steam launching x86 version under Rosetta + * mac-virtualcam: Remove unnecessary IOSurfaceLocks in Mach Server + * mac-virtualcam: Remove unnecessary use of NSAppleEventDescriptor + * mac-virtualcam: Use IOSurfaceLock on Intel-based Macs only + * mac-virtualcam: Fix random crashes in applications loading VirtualCam + * CI: Fix services check using deprecated GHA output + * CI: Update GitHub Actions for set-output deprecation + * UI: Use correct title for failed replay buffer start + * obs-frontend-api: Add theme functions +- Add new required pkgconfig(libva) build dependency + +------------------------------------------------------------------- Tue Dec 6 17:50:25 UTC 2022 - Hans-Peter Jansen <hp@urpla.net> - Explicitly require librist4 (dlopen'ed)
View file
obs-studio.spec
Changed
@@ -8,7 +8,7 @@ %endif Name: obs-studio -Version: 28.1.2 +Version: 29.0.0 Release: 0 Summary: A recording/broadcasting program Group: Productivity/Multimedia/Video/Editors and Convertors @@ -55,9 +55,10 @@ BuildRequires: pkgconfig(libavfilter) BuildRequires: pkgconfig(libavformat) BuildRequires: pkgconfig(libavutil) +BuildRequires: pkgconfig(librist) BuildRequires: pkgconfig(libswresample) BuildRequires: pkgconfig(libswscale) -BuildRequires: pkgconfig(librist) +BuildRequires: pkgconfig(libva) BuildRequires: pkgconfig(lua) BuildRequires: pkgconfig(luajit) BuildRequires: pkgconfig(srt)
View file
_service
Changed
@@ -1,7 +1,7 @@ <services> <service name="tar_scm" mode="disabled"> <param name="versionformat">@PARENT_TAG@</param> - <param name="revision">refs/tags/28.1.2</param> + <param name="revision">refs/tags/29.0.0</param> <param name="url">https://github.com/obsproject/obs-studio.git</param> <param name="scm">git</param> <param name="changesgenerate">enable</param>
View file
_servicedata
Changed
@@ -1,6 +1,6 @@ <servicedata> <service name="tar_scm"> <param name="url">https://github.com/obsproject/obs-studio.git</param> - <param name="changesrevision">c1841e43b04e662ae3be146ce10596eb7be866fa</param> + <param name="changesrevision">b51773b97b551cb409603146a97b2827d2a66ec3</param> </service> </servicedata> \ No newline at end of file
View file
obs-studio-28.1.2.tar.xz/plugins/rtmp-services/data/schema/service-schema-v3.json
Deleted
@@ -1,238 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "type": "object", - "properties": { - "format_version": { - "type": "integer", - "description": "Identifier for parsing this file.\n- v3 introduced 'ffmpeg_hls_muxer' to services/recommended/output\n - v2 introduced 'alt_names' to services" - }, - "services": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "description": "Name of the streaming service. Will be displayed in the Service dropdown.", - "minLength": 1 - }, - "common": { - "type": "boolean", - "description": "Whether or not the service is shown in the list before it is expanded to all services by the user.", - "default": false - }, - "stream_key_link": { - "$ref": "#/definitions/saneUrl", - "description": "Link where a logged-in user can find the 'stream key', presented as a button alongside the stream key field." - }, - "supported video codecs": { - "type": "array", - "description": "Video codecs that are supported by the service.", - "items": { - "type": "string", - "description": "Short-form codec names.", - "minLength": 1, - "enum": - "h264", - "hevc" - - } - }, - "supported audio codecs": { - "type": "array", - "description": "Audio codecs that are supported by the service.", - "items": { - "type": "string", - "description": "Short-form codec names.", - "minLength": 1, - "enum": - "aac", - "opus" - - } - }, - "servers": { - "type": "array", - "description": "List of servers.", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "description": "Name of the server (e.g. location, primary/backup), displayed in the Server dropdown.", - "minLength": 1 - }, - "url": { - "$ref": "#/definitions/serviceUri", - "description": "RTMP(S) or HLS URL of the ingest server.", - "minLength": 1 - } - }, - "additionalProperties": false, - "required": - "name", - "url" - - }, - "default": - { - "name": "", - "url": "" - } - , - "minItems": 1, - "additionalItems": true - }, - "recommended": { - "type": "object", - "description": "Recommended service settings. Users will be unable to choose values outside of these by default, so choose recommended values carefully.", - "properties": { - "keyint": { - "type": "integer", - "description": "Keyframe interval (seconds)." - }, - "max video bitrate": { - "type": "integer", - "description": "Highest supported video bitrate (kbps)." - }, - "max audio bitrate": { - "type": "integer", - "description": "Highest supported audio bitrate (kbps)." - }, - "x264opts": { - "type": "string", - "description": "Additional x264 encoder options. Space-separated.", - "pattern": "^(\\S+=\\S+\\s*)+$" - }, - "output": { - "type": "string", - "description": "OBS output module used.", - "enum": - "rtmp_output", - "ffmpeg_hls_muxer", - "ftl_output" - - }, - "profile": { - "type": "string", - "description": "H.264 Profile.", - "minLength": 1, - "enum": - "high", - "main", - "baseline" - - }, - "bframes": { - "type": "integer", - "description": "Maximum allowed number of B-Frames." - }, - "supported resolutions": { - "type": "array", - "description": "List of supported resolutions in format {width}x{height}", - "items": { - "$ref": "#/definitions/resolution" - }, - "minItems": 1, - "additionalItems": true - }, - "max fps": { - "type": "integer", - "description": "Maximum supported framerate." - }, - "bitrate matrix": { - "type": "array", - "description": "List of resolutions and frame rate combinations with their recommended maximum bitrate.", - "items": { - "type": "object", - "properties": { - "res": { - "$ref": "#/definitions/resolution", - "description": "Resolution in format {width}x{height}" - }, - "fps": { - "type": "integer", - "description": "Frame rate" - }, - "max bitrate": { - "type": "integer", - "description": "Maximum bitrate in kbps." - } - }, - "minItems": 1, - "additionalProperties": false, - "required": - "res", - "fps", - "max bitrate" - - }, - "default": - { - "res": "", - "fps": "", - "max bitrate": "" - } - , - "additionalItems": true - } - }, - "additionalProperties": false - }, - "more_info_link": { - "$ref": "#/definitions/saneUrl", - "description": "Link that provides additional info about the service, presented in the UI as a button next to the services dropdown." - }, - "alt_names": { - "type": "array", - "description": "Previous names of the service used for migrating existing users to the updated entry.", - "items": { - "type": "string", - "minLength": 1 - }, - "default": - "" - - } - }, - "additionalProperties": false, - "required": - "name", - "servers" - - }, - "additionalItems": true - } - }, - "additionalProperties": true, - "required": - "format_version", - "services" - , - "definitions": { - "resolution": { - "type": "string", - "pattern": "^\\d+x\\d+$", - "default": "" - }, - "saneUrl": { - "type": "string", - "format": "uri", - "pattern": "^https?://.+", - "default": "https://" - }, - "serviceUri": { - "anyOf": - { - "type": "string", - "format": "uri", - "pattern": "^(https|http|rtmps|rtmp|srt|rist)?://" - }, - { - "type": "string", - "format": "hostname" - } - - } - } -}
View file
obs-studio-28.1.2.tar.xz/.github/workflows/docs.yml -> obs-studio-29.0.0.tar.xz/.github/workflows/docs.yml
Changed
@@ -14,6 +14,10 @@ steps: - name: Checkout uses: actions/checkout@v3 + - name: Setup Environment + id: setup + run: | + echo "commitHash=$(git describe --exact-match --tags 2> /dev/null || git rev-parse --short HEAD)" >> $GITHUB_OUTPUT - name: Bump Version Number shell: bash if: github.event_name == 'push' @@ -45,7 +49,7 @@ pre_build_commands: 'pip install -Iv sphinx==5.1.1' - uses: actions/upload-artifact@v3 with: - name: OBS Studio Documentation (HTML) + name: 'OBS Studio Docs ${{ steps.setup.outputs.commitHash }}' path: | ${{ runner.temp }}/_github_home/_build !${{ runner.temp }}/_github_home/_build/.doctrees
View file
obs-studio-28.1.2.tar.xz/.github/workflows/flatpak.yml -> obs-studio-29.0.0.tar.xz/.github/workflows/flatpak.yml
Changed
@@ -50,7 +50,7 @@ env: FLATPAK_BUILD_PATH: flatpak_app/files/share container: - image: bilelmoussaoui/flatpak-github-actions:kde-6.3 + image: bilelmoussaoui/flatpak-github-actions:kde-6.4 options: --privileged strategy: matrix: @@ -68,7 +68,7 @@ echo "commitHash=$(git rev-parse --short=9 HEAD)" >> $GITHUB_OUTPUT - name: Build Flatpak Manifest - uses: bilelmoussaoui/flatpak-github-actions/flatpak-builder@master + uses: flatpak/flatpak-github-actions/flatpak-builder@v5 with: bundle: obs-studio-${{ steps.setup.outputs.commitHash }}.flatpak manifest-path: CI/flatpak/com.obsproject.Studio.json @@ -94,7 +94,7 @@ ostree commit --repo=repo --canonical-permissions --branch=screenshots/x86_64 flatpak_app/screenshots - name: Publish to Flathub Beta - uses: bilelmoussaoui/flatpak-github-actions/flat-manager@v4 + uses: flatpak/flatpak-github-actions/flat-manager@v5 if: matrix.branch == 'beta' with: flat-manager-url: https://hub.flathub.org/ @@ -102,7 +102,7 @@ token: ${{ secrets.FLATHUB_BETA_TOKEN }} - name: Publish to Flathub - uses: bilelmoussaoui/flatpak-github-actions/flat-manager@v4 + uses: flatpak/flatpak-github-actions/flat-manager@v5 if: matrix.branch == 'stable' with: flat-manager-url: https://hub.flathub.org/
View file
obs-studio-28.1.2.tar.xz/.github/workflows/main.yml -> obs-studio-29.0.0.tar.xz/.github/workflows/main.yml
Changed
@@ -18,15 +18,15 @@ CEF_HASH_MAC_ARM64: '98679b92eea6ea9959ac5aa54f46ca60681d8a86c768c35f496dbdd409bf0642' CEF_BUILD_VERSION_LINUX: '5060' CEF_BUILD_VERSION_WIN: '5060' - QT_VERSION_MAC: '6.3.1' - QT_HASH_MAC_X86_64: 'a83f72a11023b03b6cb2dc365f0a66ad9df31163bbb4fe2df32d601856a9fad3' - QT_HASH_MAC_ARM64: '2f30af90c049670a5660656adbb440668aa1b0567f75a5f29e1def9108928403' - QT_HASH_MAC_UNIVERSAL: '252e6684f43ab9c6f262c73af739e2296ce391b998da2c4ee04c254aaa07db18' - QT_VERSION_WIN: '6.3.1' - DEPS_VERSION_MAC: '2022-08-02' - DEPS_HASH_MAC_X86_64: '7637e52305e6fc53014b5aabd583f1a4490b1d97450420e977cae9a336a29525' - DEPS_HASH_MAC_ARM64: '755e0fa69b17a3ae444e1befa9d91d77e3cafe628fbd1c6333686091826595cd' - DEPS_VERSION_WIN: '2022-08-02' + QT_VERSION_MAC: '6.4.1' + QT_HASH_MAC_X86_64: 'c5ed7bc9f6e802910ec539066bcf0a8d64100fafce568071f264c88c22c5859b' + QT_HASH_MAC_ARM64: '1ce472fd1e28f947456b72b1d7ab929d6e93cb774c2928e22eca9bb751b12ccf' + QT_HASH_MAC_UNIVERSAL: '873f7c9c9f7fcee740a79c075b32a505c932c816d928807fa16f3439c610fbfd' + QT_VERSION_WIN: '6.4.1' + DEPS_VERSION_MAC: '2022-11-21' + DEPS_HASH_MAC_X86_64: 'ed0a145e88496f8975da14a07939dbe5633e60510aada34509a4aef64a66e438' + DEPS_HASH_MAC_ARM64: 'f397dc524e5ee7f85684f0b9661c45957446e28d166fcd6dfacf895c9d4d2521' + DEPS_VERSION_WIN: '2022-11-21' VLC_VERSION_MAC: '3.0.8' VLC_HASH_MAC: 'e0149ef4a20a19b9ecd87309c2d27787ee3f47dfd47c6639644bc1f6fd95bdf6' VLC_VERSION_WIN: '3.0.0-git' @@ -273,6 +273,7 @@ CI/linux/03_package_obs.sh ARTIFACT_NAME=$(basename $(/usr/bin/find build -maxdepth 1 -type f -name "obs-studio-*.deb" | sort -rn | head -1)) echo "FILE_NAME=${ARTIFACT_NAME}" >> $GITHUB_ENV + echo "DEBUG_FILE_NAME=${ARTIFACT_NAME//.deb/-dbgsym.ddeb}" >> $GITHUB_ENV - name: 'Upload build Artifact' if: ${{ success() && (github.event_name != 'pull_request' || env.SEEKING_TESTERS == '1') }} @@ -281,6 +282,13 @@ name: 'obs-studio-${{ matrix.ubuntu }}-${{ steps.setup.outputs.commitHash }}' path: '${{ github.workspace }}/obs-studio/build/${{ env.FILE_NAME }}' + - name: 'Upload debug symbol Artifact' + if: ${{ success() && (github.event_name != 'pull_request' || env.SEEKING_TESTERS == '1') }} + uses: actions/upload-artifact@v3 + with: + name: 'obs-studio-${{ matrix.ubuntu }}-${{ steps.setup.outputs.commitHash }}-dbgsym' + path: '${{ github.workspace }}/obs-studio/build/${{ env.DEBUG_FILE_NAME }}' + windows_build: name: '02 - Windows' runs-on: windows-2022 @@ -362,7 +370,7 @@ path: '${{ env.FILE_NAME }}' linux_package: - name: '02 - Flatpak Bundle' + name: '02 - Flatpak' runs-on: ubuntu-latest needs: clang_check if: always() @@ -370,7 +378,7 @@ run: shell: bash container: - image: bilelmoussaoui/flatpak-github-actions:kde-6.3 + image: bilelmoussaoui/flatpak-github-actions:kde-6.4 options: --privileged steps: - name: 'Check for Github Labels' @@ -385,13 +393,11 @@ - name: 'Checkout' uses: actions/checkout@v3 - if: ${{ success() && (github.event_name != 'pull_request' || env.SEEKING_TESTERS == '1') }} with: submodules: 'recursive' fetch-depth: 0 - name: 'Setup build environment' - if: ${{ success() && (github.event_name != 'pull_request' || env.SEEKING_TESTERS == '1') }} run: | git config --global --add safe.directory $GITHUB_WORKSPACE echo "OBS_GIT_BRANCH=$(git rev-parse --abbrev-ref HEAD)" >> $GITHUB_ENV @@ -399,9 +405,9 @@ echo "OBS_GIT_TAG=$(git describe --tags --abbrev=0)" >> $GITHUB_ENV - name: Build Flatpak Manifest - uses: bilelmoussaoui/flatpak-github-actions/flatpak-builder@v4 - if: ${{ success() && (github.event_name != 'pull_request' || env.SEEKING_TESTERS == '1') }} + uses: flatpak/flatpak-github-actions/flatpak-builder@v5 with: + build-bundle: ${{ github.event_name != 'pull_request' || env.SEEKING_TESTERS == '1' }} bundle: obs-studio-flatpak-${{ env.OBS_GIT_HASH }}.flatpak manifest-path: CI/flatpak/com.obsproject.Studio.json cache-key: flatpak-builder-${{ hashFiles('CI/flatpak/com.obsproject.Studio.json') }}
View file
obs-studio-28.1.2.tar.xz/.github/workflows/services-json.yml -> obs-studio-29.0.0.tar.xz/.github/workflows/services-json.yml
Changed
@@ -17,6 +17,7 @@ schema: name: Schema runs-on: ubuntu-20.04 + if: ${{ github.repository_owner == 'obsproject' || github.event_name != 'schedule' }} steps: - name: Checkout uses: actions/checkout@v3 @@ -46,7 +47,7 @@ name: Service Check runs-on: ubuntu-20.04 needs: schema - if: ${{ github.repository_owner == 'obsproject' && (github.event_name == 'schedule' || github.event_name == 'workflow_dispatch') }} + if: ${{ github.repository_owner == 'obsproject' && github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' }} steps: - name: Checkout
View file
obs-studio-28.1.2.tar.xz/.github/workflows/steam.yml -> obs-studio-29.0.0.tar.xz/.github/workflows/steam.yml
Changed
@@ -27,6 +27,7 @@ STEAM_NIGHTLY_BRANCH: nightly STEAM_STABLE_BRANCH: staging STEAM_BETA_BRANCH: beta_staging + STEAM_PLAYTEST_BRANCH: staging SEVENZIP_HASH: 5290409e7bbe2f133d0bd7e7482548678157ea2be276b0f9cb440600f4be9a2d jobs: @@ -145,8 +146,14 @@ run: | if '${{ steps.build-info.outputs.type }}' == 'release' || '${{ steps.cache.outputs.cache-hit }}' != 'true' ; then echo "result=true" >> $GITHUB_OUTPUT + if '${{ steps.build-info.outputs.branch }}' == '${{ env.STEAM_BETA_BRANCH }}' ; then + echo "result_playtest=true" >> $GITHUB_OUTPUT + else + echo "result_playtest=false" >> $GITHUB_OUTPUT + fi else echo "result=false" >> $GITHUB_OUTPUT + echo "result_playtest=false" >> $GITHUB_OUTPUT fi - name: Download and prepare builds @@ -256,6 +263,26 @@ steamcmd +login '${{ secrets.STEAM_USER }}' '${{ secrets.STEAM_PASSWORD }}' '${{ steps.steam-totp.outputs.code }}' +run_app_build "$(pwd)/build.vdf" +quit echo "::endgroup::" + - name: Generate Steam auth code (Playtest) + if: steps.should-run.outputs.result_playtest == 'true' + id: steam-totp-playtest + uses: CyberAndrii/steam-totp@0fc9e59dc5bbf4368d23d5a33956f104248da31a + with: + shared_secret: ${{ secrets.STEAM_SHARED_SECRET }} + + - name: Upload to Steam (Playtest) + if: steps.should-run.outputs.result_playtest == 'true' + run: | + cd steam + echo "::group::Prepare Steam build script" + sed 's/@@DESC@@/${{ steps.build-info.outputs.branch }}-${{ steps.build-info.outputs.desc }}/;s/@@BRANCH@@/${{ env.STEAM_PLAYTEST_BRANCH }}/' ../source/CI/steam/obs_playtest_build.vdf > build_playtest.vdf + echo "Generated file:" + cat build_playtest.vdf + echo "::endgroup::" + echo "::group::Upload to Steam" + steamcmd +login '${{ secrets.STEAM_USER }}' '${{ secrets.STEAM_PASSWORD }}' '${{ steps.steam-totp-playtest.outputs.code }}' +run_app_build "$(pwd)/build_playtest.vdf" +quit + echo "::endgroup::" + - name: Upload Steam build logs if: steps.should-run.outputs.result == 'true' uses: actions/upload-artifact@v3
View file
obs-studio-28.1.2.tar.xz/CI/check-services.py -> obs-studio-29.0.0.tar.xz/CI/check-services.py
Changed
@@ -87,7 +87,13 @@ """Try connecting and sending a RTMP handshake (with SSL if necessary)""" parsed = urlparse(uri) hostname, port = parsed.netloc.partition(':')::2 - port = int(port) if port else 1935 + + if port: + port = int(port) + elif parsed.scheme == 'rtmps': + port = 443 + else: + port = 1935 try: recv = b''
View file
obs-studio-28.1.2.tar.xz/CI/flatpak/com.obsproject.Studio.json -> obs-studio-29.0.0.tar.xz/CI/flatpak/com.obsproject.Studio.json
Changed
@@ -1,7 +1,7 @@ { "app-id": "com.obsproject.Studio", "runtime": "org.kde.Platform", - "runtime-version": "6.3", + "runtime-version": "6.4", "sdk": "org.kde.Sdk", "command": "obs", "finish-args": @@ -19,7 +19,7 @@ "--talk-name=org.a11y.Bus", "--own-name=org.kde.StatusNotifierItem-2-2", "--system-talk-name=org.freedesktop.Avahi", - "--env=VST_PATH=/app/extensions/Plugins/lxvst" + "--env=VST_PATH=/app/extensions/Plugins/vst" , "add-extensions": { "com.obsproject.Studio.Plugin": { @@ -32,9 +32,9 @@ }, "org.freedesktop.LinuxAudio.Plugins": { "directory": "extensions/Plugins", - "version": "21.08", + "version": "22.08", "add-ld-path": "lib", - "merge-dirs": "lxvst", + "merge-dirs": "vst", "subdirectories": true, "no-autodownload": true } @@ -58,7 +58,7 @@ { "type": "git", "url": "https://code.videolan.org/videolan/x264.git", - "commit": "baee400fa9ced6f5481a728138fed6e867b0ff7f" + "commit": "b093bbe7d9bc642c8f24067cbdcc73bb43562eab" } }, @@ -119,8 +119,8 @@ { "type": "git", "url": "https://github.com/Haivision/srt.git", - "tag": "v1.5.0", - "commit": "060c0d1a2af8082c053018fa6a6fe2dba67d71a8" + "tag": "v1.5.1", + "commit": "0bc3b03202b3159fc9b085b3ae6d66ec071c25d6" } }, @@ -191,8 +191,8 @@ { "type": "git", "url": "https://aomedia.googlesource.com/aom.git", - "commit": "fc430c57c7b0307b4c5ffb686cd90b3c010d08d2", - "tag": "v3.4.0" + "commit": "bcfe6fbfed315f83ee8a95465c654ee8078dbff9", + "tag": "v3.5.0" } }, @@ -216,8 +216,8 @@ { "type": "git", "url": "https://gitlab.com/AOMediaCodec/SVT-AV1.git", - "tag": "v1.1.0", - "commit": "6e87a1de98281840abebc030781780edd822bae5" + "tag": "v1.3.0", + "commit": "91b94efb2809e83d9bf041d8575b32f234dfef27" } }, @@ -248,22 +248,20 @@ { "type": "git", "url": "https://github.com/FFmpeg/FFmpeg.git", - "commit": "9687cae2b468e09e35df4cea92cc2e6a0e6c93b3", + "commit": "eacfcbae690f914a4b1b4ad06999f138540cc3d8", "disable-shallow-clone": true }, { "type": "git", "dest": "obs-deps", "url": "https://github.com/obsproject/obs-deps.git", - "tag": "2022-07-29", - "commit": "71df2dddb0eb732496448f626553b61bcda8f993" + "tag": "2022-11-21", + "commit": "ba56d64e4cbcc0aec4fa0efcef5f5a1e6a1ba91d" }, { "type": "shell", "commands": - "patch -Np1 -i obs-deps/deps.ffmpeg/patches/FFmpeg/0001-FFmpeg-9010.patch", - "patch -Np1 -i obs-deps/deps.ffmpeg/patches/FFmpeg/0002-FFmpeg-5.0.1-OBS.patch", - "patch -Np1 -i obs-deps/deps.ffmpeg/patches/FFmpeg/0003-FFmpeg-5.0.1-librist-7f3f3539e8.patch" + "patch -Np1 -i obs-deps/deps.ffmpeg/patches/FFmpeg/0001-FFmpeg-5.1.2-OBS.patch" } @@ -281,7 +279,7 @@ { "type": "git", "url": "https://luajit.org/git/luajit-2.0.git", - "commit": "3065c910ad6027031aabe2dfd3c26a3d0f014b4f", + "commit": "7a0cf5fd4c6c841d0455a51271af4fd4390c7884", "disable-shallow-clone": true }, { @@ -333,56 +331,47 @@ }, { - "name": "pipewire", - "buildsystem": "meson", + "name": "ntv2", + "buildsystem": "cmake-ninja", + "builddir": true, "config-opts": - "-Daudiotestsrc=disabled", - "-Droc=disabled", - "-Dvideotestsrc=disabled", - "-Dvolume=disabled", - "-Dvulkan=disabled", - "-Ddocs=disabled", - "-Dman=disabled", - "-Dbluez5-codec-ldac=disabled", - "-Dbluez5-codec-aptx=disabled", - "-Dlibcamera=disabled", - "-Dudevrulesdir=/app/lib/udev/rules.d/", - "-Dsession-managers=", - "-Dtests=disabled", - "-Dexamples=disabled", - "-Dpw-cat=disabled" + "-DCMAKE_BUILD_TYPE=Release", + "-DAJA_BUILD_OPENSOURCE=ON", + "-DAJA_BUILD_APPS=OFF", + "-DAJA_INSTALL_HEADERS=ON" , "cleanup": - "/bin" + "/include" , "sources": { "type": "git", - "url": "https://github.com/pipewire/pipewire.git", - "tag": "0.3.40", - "commit": "7afd80052b7c49754a13c9ab49c368f95b60e0a7" + "url": "https://github.com/aja-video/ntv2.git", + "tag": "v16.2-bugfix5", + "commit": "0acbac70a0b5e6509cca78cfbf69974c73c10db9" } }, { - "name": "ntv2", + "name": "jansson", "buildsystem": "cmake-ninja", "builddir": true, "config-opts": - "-DCMAKE_BUILD_TYPE=Release", - "-DAJA_BUILD_OPENSOURCE=ON", - "-DAJA_BUILD_APPS=OFF", - "-DAJA_INSTALL_HEADERS=ON" + "-DJANSSON_EXAMPLES=OFF", + "-DJANSSON_BUILD_DOCS=OFF", + "-DJANSSON_BUILD_SHARED_LIBS=ON", + "-DJANSSON_WITHOUT_TESTS=ON" , "cleanup": - "/include" + "/include", + "/lib/pkgconfig" , "sources": { "type": "git", - "url": "https://github.com/aja-video/ntv2.git", - "tag": "v16.2-bugfix5", - "commit": "0acbac70a0b5e6509cca78cfbf69974c73c10db9" + "url": "https://github.com/akheron/jansson.git", + "tag": "v2.14", + "commit": "684e18c927e89615c2d501737e90018f4930d6c5" } },
View file
obs-studio-28.1.2.tar.xz/CI/linux/03_package_obs.sh -> obs-studio-29.0.0.tar.xz/CI/linux/03_package_obs.sh
Changed
@@ -21,9 +21,14 @@ cmake --build ${BUILD_DIR} -t package DEB_NAME=$(find ${BUILD_DIR} -maxdepth 1 -type f -name "obs*.deb" | sort -rn | head -1) + DEBUG_NAME="${DEB_NAME//.deb/-dbgsym.ddeb}" if "${DEB_NAME}" ; then - mv ${DEB_NAME} ${BUILD_DIR}/${FILE_NAME} + mv "${DEB_NAME}" "${BUILD_DIR}/${FILE_NAME}" + + if "${DEBUG_NAME}" ; then + mv "${DEBUG_NAME}" "${BUILD_DIR}/${FILE_NAME//.deb/-dbgsym.ddeb}" + fi else error "ERROR No suitable OBS debian package generated" fi
View file
obs-studio-29.0.0.tar.xz/CI/steam/obs_playtest_build.vdf
Added
@@ -0,0 +1,35 @@ +"AppBuild" +{ + "AppID" "1905640" + "Desc" "github_@@DESC@@" + + "ContentRoot" "./" + "BuildOutput" "build/" + + "SetLive" "@@BRANCH@@" + + "Depots" + { + "1905642" // Windows + { + "ContentRoot" "./steam-windows" + "FileMapping" + { + "LocalPath" "*" + "DepotPath" "." + "recursive" "1" + } + } + + "1905641" // Mac + { + "ContentRoot" "./steam-macos" + "FileMapping" + { + "LocalPath" "*" + "DepotPath" "." + "recursive" "1" + } + } + } +}
View file
obs-studio-28.1.2.tar.xz/CI/windows/02_build_obs.ps1 -> obs-studio-29.0.0.tar.xz/CI/windows/02_build_obs.ps1
Changed
@@ -63,31 +63,59 @@ $BuildDirectoryActual = "${BuildDirectory}$(if (${BuildArch} -eq "x64") { "64" } else { "32" })" $GeneratorPlatform = "$(if (${BuildArch} -eq "x64") { "x64" } else { "Win32" })" - $CmakeCommand = @( - "-G", ${CmakeGenerator} - "-DCMAKE_GENERATOR_PLATFORM=`"${GeneratorPlatform}`"", - "-DCMAKE_SYSTEM_VERSION=`"${CmakeSystemVersion}`"", - "-DCMAKE_PREFIX_PATH:PATH=`"${CmakePrefixPath}`"", - "-DCEF_ROOT_DIR:PATH=`"${CefDirectory}`"", - "-DENABLE_BROWSER=ON", - "-DVLC_PATH:PATH=`"${CheckoutDir}/../obs-build-dependencies/vlc-${WindowsVlcVersion}`"", - "-DENABLE_VLC=ON", - "-DCMAKE_INSTALL_PREFIX=`"${BuildDirectoryActual}/install`"", - "-DVIRTUALCAM_GUID=`"${Env:VIRTUALCAM-GUID}`"", - "-DTWITCH_CLIENTID=`"${Env:TWITCH_CLIENTID}`"", - "-DTWITCH_HASH=`"${Env:TWITCH_HASH}`"", - "-DRESTREAM_CLIENTID=`"${Env:RESTREAM_CLIENTID}`"", - "-DRESTREAM_HASH=`"${Env:RESTREAM_HASH}`"", - "-DYOUTUBE_CLIENTID=`"${Env:YOUTUBE_CLIENTID}`"", - "-DYOUTUBE_CLIENTID_HASH=`"${Env:YOUTUBE_CLIENTID_HASH}`"", - "-DYOUTUBE_SECRET=`"${Env:YOUTUBE_SECRET}`"", - "-DYOUTUBE_SECRET_HASH=`"${Env:YOUTUBE_SECRET_HASH}`"", - "-DCOPIED_DEPENDENCIES=OFF", - "-DCOPY_DEPENDENCIES=ON", - "-DBUILD_FOR_DISTRIBUTION=`"$(if (Test-Path Env:BUILD_FOR_DISTRIBUTION) { "ON" } else { "OFF" })`"", - "$(if (Test-Path Env:CI) { "-DOBS_BUILD_NUMBER=${Env:GITHUB_RUN_ID}" })", - "$(if (Test-Path Variable:$Quiet) { "-Wno-deprecated -Wno-dev --log-level=ERROR" })" - ) + if ( $PSVersionTable.PSVersion -ge '7.3.0' ) { + $CmakeCommand = @( + "-G", ${CmakeGenerator} + "-DCMAKE_GENERATOR_PLATFORM=${GeneratorPlatform}", + "-DCMAKE_SYSTEM_VERSION=${CmakeSystemVersion}", + "-DCMAKE_PREFIX_PATH:PATH=${CmakePrefixPath}", + "-DCEF_ROOT_DIR:PATH=${CefDirectory}", + "-DENABLE_BROWSER=ON", + "-DVLC_PATH:PATH=${CheckoutDir}/../obs-build-dependencies/vlc-${WindowsVlcVersion}", + "-DENABLE_VLC=ON", + "-DCMAKE_INSTALL_PREFIX=${BuildDirectoryActual}/install", + "-DVIRTUALCAM_GUID=${Env:VIRTUALCAM-GUID}", + "-DTWITCH_CLIENTID=${Env:TWITCH_CLIENTID}", + "-DTWITCH_HASH=${Env:TWITCH_HASH}", + "-DRESTREAM_CLIENTID=${Env:RESTREAM_CLIENTID}", + "-DRESTREAM_HASH=${Env:RESTREAM_HASH}", + "-DYOUTUBE_CLIENTID=${Env:YOUTUBE_CLIENTID}", + "-DYOUTUBE_CLIENTID_HASH=${Env:YOUTUBE_CLIENTID_HASH}", + "-DYOUTUBE_SECRET=${Env:YOUTUBE_SECRET}", + "-DYOUTUBE_SECRET_HASH=${Env:YOUTUBE_SECRET_HASH}", + "-DCOPIED_DEPENDENCIES=OFF", + "-DCOPY_DEPENDENCIES=ON", + "-DBUILD_FOR_DISTRIBUTION=$(if (Test-Path Env:BUILD_FOR_DISTRIBUTION) { "ON" } else { "OFF" })", + "$(if (Test-Path Env:CI) { "-DOBS_BUILD_NUMBER=${Env:GITHUB_RUN_ID}" })", + "$(if (Test-Path Variable:$Quiet) { "-Wno-deprecated -Wno-dev --log-level=ERROR" })" + ) + } else { + $CmakeCommand = @( + "-G", ${CmakeGenerator} + "-DCMAKE_GENERATOR_PLATFORM=`"${GeneratorPlatform}`"", + "-DCMAKE_SYSTEM_VERSION=`"${CmakeSystemVersion}`"", + "-DCMAKE_PREFIX_PATH:PATH=`"${CmakePrefixPath}`"", + "-DCEF_ROOT_DIR:PATH=`"${CefDirectory}`"", + "-DENABLE_BROWSER=ON", + "-DVLC_PATH:PATH=`"${CheckoutDir}/../obs-build-dependencies/vlc-${WindowsVlcVersion}`"", + "-DENABLE_VLC=ON", + "-DCMAKE_INSTALL_PREFIX=`"${BuildDirectoryActual}/install`"", + "-DVIRTUALCAM_GUID=`"${Env:VIRTUALCAM-GUID}`"", + "-DTWITCH_CLIENTID=`"${Env:TWITCH_CLIENTID}`"", + "-DTWITCH_HASH=`"${Env:TWITCH_HASH}`"", + "-DRESTREAM_CLIENTID=`"${Env:RESTREAM_CLIENTID}`"", + "-DRESTREAM_HASH=`"${Env:RESTREAM_HASH}`"", + "-DYOUTUBE_CLIENTID=`"${Env:YOUTUBE_CLIENTID}`"", + "-DYOUTUBE_CLIENTID_HASH=`"${Env:YOUTUBE_CLIENTID_HASH}`"", + "-DYOUTUBE_SECRET=`"${Env:YOUTUBE_SECRET}`"", + "-DYOUTUBE_SECRET_HASH=`"${Env:YOUTUBE_SECRET_HASH}`"", + "-DCOPIED_DEPENDENCIES=OFF", + "-DCOPY_DEPENDENCIES=ON", + "-DBUILD_FOR_DISTRIBUTION=`"$(if (Test-Path Env:BUILD_FOR_DISTRIBUTION) { "ON" } else { "OFF" })`"", + "$(if (Test-Path Env:CI) { "-DOBS_BUILD_NUMBER=${Env:GITHUB_RUN_ID}" })", + "$(if (Test-Path Variable:$Quiet) { "-Wno-deprecated -Wno-dev --log-level=ERROR" })" + ) + } Invoke-External cmake -S . -B "${BuildDirectoryActual}" @CmakeCommand
View file
obs-studio-28.1.2.tar.xz/UI/api-interface.cpp -> obs-studio-29.0.0.tar.xz/UI/api-interface.cpp
Changed
@@ -642,6 +642,26 @@ return Str(string); } + bool obs_frontend_is_theme_dark(void) override + { + return App()->IsThemeDark(); + } + + char *obs_frontend_get_last_recording(void) override + { + return bstrdup(main->outputHandler->lastRecordingPath.c_str()); + } + + char *obs_frontend_get_last_screenshot(void) override + { + return bstrdup(main->lastScreenshot.c_str()); + } + + char *obs_frontend_get_last_replay(void) override + { + return bstrdup(main->lastReplay.c_str()); + } + void on_load(obs_data_t *settings) override { for (size_t i = saveCallbacks.size(); i > 0; i--) {
View file
obs-studio-28.1.2.tar.xz/UI/context-bar-controls.cpp -> obs-studio-29.0.0.tar.xz/UI/context-bar-controls.cpp
Changed
@@ -311,10 +311,12 @@ const char *device_str = get_os_text(mod, "Monitor", "DisplayCapture.Display", "Screen"); ui->deviceLabel->setText(device_str); +#ifndef _WIN32 is_int = true; +#endif #ifdef _WIN32 - prop_name = "monitor"; + prop_name = "monitor_id"; #elif __APPLE__ prop_name = "display"; #else
View file
obs-studio-28.1.2.tar.xz/UI/data/locale/en-US.ini -> obs-studio-29.0.0.tar.xz/UI/data/locale/en-US.ini
Changed
@@ -113,6 +113,7 @@ SourceProperties="Open Source Properties" SourceFilters="Open Source Filters" MixerToolbarMenu="Audio Mixer Menu" +SceneFilters="Open Scene Filters" # warning for plugin load failures PluginsFailedToLoad.Title="Plugin Load Error" @@ -204,6 +205,7 @@ Basic.AutoConfig.StreamPage.Service.Custom="Custom..." Basic.AutoConfig.StreamPage.Server="Server" Basic.AutoConfig.StreamPage.StreamKey="Stream Key" +Basic.AutoConfig.StreamPage.StreamKey.ToolTip="RIST: enter the encryption passphrase.\nRTMP: enter the key provided by the service.\nSRT: enter the streamid if the service uses one." Basic.AutoConfig.StreamPage.StreamKey.LinkToSite="(Link)" Basic.AutoConfig.StreamPage.EncoderKey="Encoder Key" Basic.AutoConfig.StreamPage.ConnectedAccount="Connected account" @@ -266,6 +268,8 @@ Updater.Running.Text="Outputs are currently active, please shut down any active outputs before attempting to update" Updater.NoUpdatesAvailable.Title="No updates available" Updater.NoUpdatesAvailable.Text="No updates are currently available" +Updater.BranchNotFound.Title="Update Channel Removed" +Updater.BranchNotFound.Text="Your selected update channel is no longer available, OBS has been reset to the default." Updater.RepairButUpdatesAvailable.Title="Integrity Check Unavailable" Updater.RepairButUpdatesAvailable.Text="Checking file integrity is only possible for the latest version available. Use Help → Check For Updates to verify and update your OBS installation." Updater.RepairConfirm.Title="Confirm Integrity Check" @@ -833,6 +837,10 @@ Basic.Settings.General="General" Basic.Settings.General.Theme="Theme" Basic.Settings.General.Language="Language" +Basic.Settings.General.Updater="Updates" +Basic.Settings.General.UpdateChannel="Update Channel" +Basic.Settings.General.UpdateChannelDisabled="(Disabled)" +Basic.Settings.General.UpdateChannelDefault="(Default)" Basic.Settings.General.EnableAutoUpdates="Automatically check for updates on startup" Basic.Settings.General.OpenStatsOnStartup="Open stats dialog on startup" Basic.Settings.General.HideOBSWindowsFromCapture="Hide OBS windows from screen capture" @@ -884,12 +892,20 @@ Basic.Settings.General.MultiviewLayout.16Scene="Scenes only (16 Scenes)" Basic.Settings.General.MultiviewLayout.25Scene="Scenes only (25 Scenes)" +# default channel name translations +Basic.Settings.General.ChannelName.stable="Stable" +Basic.Settings.General.ChannelDescription.stable="Latest stable release" +Basic.Settings.General.ChannelName.beta="Betas / Release Candidates" +Basic.Settings.General.ChannelDescription.beta="Potentially unstable pre-release versions" + # basic mode 'stream' settings 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.Custom.Username.ToolTip="RIST: enter the srp_username.\nRTMP: enter the username.\nSRT: not used." +Basic.Settings.Stream.Custom.Password.ToolTip="RIST: enter the srp_password.\nRTMP: enter the password.\nSRT: enter the encryption passphrase." Basic.Settings.Stream.BandwidthTestMode="Enable Bandwidth Test Mode" Basic.Settings.Stream.TTVAddon="Twitch Chat Add-Ons" Basic.Settings.Stream.TTVAddon.None="None" @@ -926,6 +942,7 @@ 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.EstimateTooLarge="Warning: Estimated memory usage of %1 MiB is larger than recommended maximum of %2 MiB" 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" @@ -944,12 +961,15 @@ 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.H264="Hardware (QSV, H.264)" +Basic.Settings.Output.Simple.Encoder.Hardware.QSV.AV1="Hardware (QSV, AV1)" Basic.Settings.Output.Simple.Encoder.Hardware.AMD.H264="Hardware (AMD, H.264)" Basic.Settings.Output.Simple.Encoder.Hardware.AMD.HEVC="Hardware (AMD, HEVC)" +Basic.Settings.Output.Simple.Encoder.Hardware.AMD.AV1="Hardware (AMD, AV1)" Basic.Settings.Output.Simple.Encoder.Hardware.NVENC.H264="Hardware (NVENC, H.264)" Basic.Settings.Output.Simple.Encoder.Hardware.NVENC.AV1="Hardware (NVENC, AV1)" Basic.Settings.Output.Simple.Encoder.Hardware.NVENC.HEVC="Hardware (NVENC, HEVC)" Basic.Settings.Output.Simple.Encoder.Hardware.Apple.H264="Hardware (Apple, H.264)" +Basic.Settings.Output.Simple.Encoder.Hardware.Apple.HEVC="Hardware (Apple, HEVC)" 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" @@ -1046,7 +1066,6 @@ Basic.Settings.Video.ScaledResolution="Output (Scaled) Resolution" Basic.Settings.Video.DownscaleFilter="Downscale Filter" Basic.Settings.Video.DownscaleFilter.Unavailable="Resolutions match, no downscaling required" -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" @@ -1056,7 +1075,6 @@ Basic.Settings.Video.Renderer="Renderer" Basic.Settings.Video.InvalidResolution="Invalid resolution value. Must be widthxheight (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" # scale filters Basic.Settings.Video.DownscaleFilter.Bilinear="Bilinear (Fastest, but blurry if scaling)" @@ -1135,7 +1153,7 @@ Basic.Settings.Advanced.Video.ColorFormat.I444="I444 (8-bit, 4:4:4, 3 planes)" Basic.Settings.Advanced.Video.ColorFormat.P010="P010 (10-bit, 4:2:0, 2 planes)" Basic.Settings.Advanced.Video.ColorFormat.I010="I010 (10-bit, 4:2:0, 3 planes)" -Basic.Settings.Advanced.Video.ColorFormat.RGB="RGB (8-bit)" +Basic.Settings.Advanced.Video.ColorFormat.BGRA="BGRA (8-bit)" Basic.Settings.Advanced.Video.ColorSpace="Color Space" Basic.Settings.Advanced.Video.ColorSpace.sRGB="sRGB" Basic.Settings.Advanced.Video.ColorSpace.601="Rec. 601" @@ -1164,7 +1182,7 @@ 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="Automatically remux to %1" Basic.Settings.Advanced.AutoRemux.MP4="(record as mkv)" # advanced audio properties @@ -1254,6 +1272,7 @@ # Output warnings 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 finalized (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.ProResRecording="Apple ProRes is not supported by the %1 container format - supported container formats are mov (preferred) and mkv." OutputWarnings.CannotPause="Warning: Recordings cannot be paused if the recording encoder is set to \"(Use stream encoder)\"" # deleting final scene
View file
obs-studio-28.1.2.tar.xz/UI/data/themes/Acri.qss -> obs-studio-29.0.0.tar.xz/UI/data/themes/Acri.qss
Changed
@@ -524,6 +524,10 @@ qproperty-icon: url(./Dark/media-pause.svg); } +* themeID="filtersIcon" { + qproperty-icon: url(./Dark/filter.svg); +} + QToolBarExtension { background: palette(button); min-width: 12px; @@ -819,7 +823,7 @@ background-color: rgb(22,31,65); } -QPushButton:disabled { +QPushButton:disabled, QToolButton:disabled { background-color: rgb(22,31,65); } @@ -1519,3 +1523,8 @@ OBSBasicStats { background: palette(dark); } + +/* Advanced audio dialog */ +OBSBasicAdvAudio #scrollAreaWidgetContents { + background: palette(dark); +}
View file
obs-studio-28.1.2.tar.xz/UI/data/themes/Dark.qss -> obs-studio-29.0.0.tar.xz/UI/data/themes/Dark.qss
Changed
@@ -328,6 +328,10 @@ qproperty-icon: url(./Dark/cogs.svg); } +* themeID="filtersIcon" { + qproperty-icon: url(./Dark/filter.svg); +} + /* Tab Widget */ QTabWidget::pane { /* The tab widget frame */ @@ -530,7 +534,7 @@ background-color: palette(base); } -QPushButton:disabled { +QPushButton:disabled, QToolButton:disabled { background-color: rgb(46,45,46); }
View file
obs-studio-28.1.2.tar.xz/UI/data/themes/Grey.qss -> obs-studio-29.0.0.tar.xz/UI/data/themes/Grey.qss
Changed
@@ -522,6 +522,10 @@ qproperty-icon: url(./Dark/media-pause.svg); } +* themeID="filtersIcon" { + qproperty-icon: url(./Dark/filter.svg); +} + QToolBarExtension { background: palette(button); min-width: 12px; @@ -808,7 +812,7 @@ background-color: rgb(28,28,28); } -QPushButton:disabled { +QPushButton:disabled, QToolButton:disabled { background-color: rgb(28,28,28); } @@ -1507,3 +1511,8 @@ OBSBasicStats { background: palette(dark); } + +/* Advanced audio dialog */ +OBSBasicAdvAudio #scrollAreaWidgetContents { + background: palette(dark); +}
View file
obs-studio-28.1.2.tar.xz/UI/data/themes/Light.qss -> obs-studio-29.0.0.tar.xz/UI/data/themes/Light.qss
Changed
@@ -522,6 +522,10 @@ qproperty-icon: url(./Light/media-pause.svg); } +* themeID="filtersIcon" { + qproperty-icon: url(./Light/filter.svg); +} + QToolBarExtension { background: palette(button); min-width: 12px; @@ -808,7 +812,7 @@ background-color: rgb(193,193,193); } -QPushButton:disabled { +QPushButton:disabled, QToolButton:disabled { background-color: rgb(193,193,193); } @@ -1513,3 +1517,8 @@ OBSBasicStats { background: palette(dark); } + +/* Advanced audio dialog */ +OBSBasicAdvAudio #scrollAreaWidgetContents { + background: palette(dark); +}
View file
obs-studio-28.1.2.tar.xz/UI/data/themes/Rachni.qss -> obs-studio-29.0.0.tar.xz/UI/data/themes/Rachni.qss
Changed
@@ -530,6 +530,10 @@ qproperty-icon: url(./Dark/media-pause.svg); } +* themeID="filtersIcon" { + qproperty-icon: url(./Dark/filter.svg); +} + QToolBarExtension { background: palette(button); min-width: 12px; @@ -812,7 +816,7 @@ background-color: rgb(240,98,146); } -QPushButton:disabled { +QPushButton:disabled, QToolButton:disabled { background-color: rgb(0,139,163); } @@ -1511,3 +1515,8 @@ OBSBasicStats { background: palette(dark); } + +/* Advanced audio dialog */ +OBSBasicAdvAudio #scrollAreaWidgetContents { + background: palette(dark); +}
View file
obs-studio-28.1.2.tar.xz/UI/data/themes/System.qss -> obs-studio-29.0.0.tar.xz/UI/data/themes/System.qss
Changed
@@ -58,6 +58,10 @@ qproperty-icon: url(:/res/images/cogs.svg); } +* themeID="filtersIcon" { + qproperty-icon: url(:/res/images/filter.svg); +} + MuteCheckBox { outline: none; }
View file
obs-studio-28.1.2.tar.xz/UI/data/themes/Yami.qss -> obs-studio-29.0.0.tar.xz/UI/data/themes/Yami.qss
Changed
@@ -526,6 +526,10 @@ qproperty-icon: url(./Dark/media-pause.svg); } +* themeID="filtersIcon" { + qproperty-icon: url(./Dark/filter.svg); +} + QToolBarExtension { background: palette(button); min-width: 12px; @@ -812,7 +816,7 @@ background-color: rgb(25,27,38); } -QPushButton:disabled { +QPushButton:disabled, QToolButton:disabled { background-color: rgb(25,27,38); } @@ -1511,3 +1515,8 @@ OBSBasicStats { background: palette(dark); } + +/* Advanced audio dialog */ +OBSBasicAdvAudio #scrollAreaWidgetContents { + background: palette(dark); +}
View file
obs-studio-28.1.2.tar.xz/UI/forms/OBSBasic.ui -> obs-studio-29.0.0.tar.xz/UI/forms/OBSBasic.ui
Changed
@@ -842,6 +842,8 @@ <addaction name="actionAddScene"/> <addaction name="actionRemoveScene"/> <addaction name="separator"/> + <addaction name="actionSceneFilters"/> + <addaction name="separator"/> <addaction name="actionSceneUp"/> <addaction name="actionSceneDown"/> </widget> @@ -979,6 +981,7 @@ </property> <addaction name="actionAddSource"/> <addaction name="actionRemoveSource"/> + <addaction name="separator"/> <addaction name="actionSourceProperties"/> <addaction name="separator"/> <addaction name="actionSourceUp"/> @@ -2348,6 +2351,21 @@ <string>menuIconSmall</string> </property> </action> + <action name="actionSceneFilters"> + <property name="icon"> + <iconset resource="obs.qrc"> + <normaloff>:/res/images/filter.svg</normaloff>:/res/images/filter.svg</iconset> + </property> + <property name="text"> + <string>SceneFilters</string> + </property> + <property name="toolTip"> + <string>SceneFilters</string> + </property> + <property name="themeID" stdset="0"> + <string>filtersIcon</string> + </property> + </action> </widget> <customwidgets> <customwidget>
View file
obs-studio-28.1.2.tar.xz/UI/forms/OBSBasicSettings.ui -> obs-studio-29.0.0.tar.xz/UI/forms/OBSBasicSettings.ui
Changed
@@ -256,23 +256,13 @@ </spacer> </item> <item row="2" column="1"> - <widget class="QCheckBox" name="enableAutoUpdates"> - <property name="text"> - <string>Basic.Settings.General.EnableAutoUpdates</string> - </property> - <property name="checked"> - <bool>true</bool> - </property> - </widget> - </item> - <item row="3" column="1"> <widget class="QCheckBox" name="openStatsOnStartup"> <property name="text"> <string>Basic.Settings.General.OpenStatsOnStartup</string> </property> </widget> </item> - <item row="4" column="1"> + <item row="3" column="1"> <widget class="QCheckBox" name="hideOBSFromCapture"> <property name="toolTip"> <string>Basic.Settings.General.HideOBSWindowsFromCapture.Tooltip</string> @@ -286,6 +276,64 @@ </widget> </item> <item> + <widget class="QGroupBox" name="updateSettingsGroupBox"> + <property name="title"> + <string>Basic.Settings.General.Updater</string> + </property> + <layout class="QFormLayout" name="formLayout_20"> + <property name="labelAlignment"> + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + <property name="fieldGrowthPolicy"> + <enum>QFormLayout::AllNonFixedFieldsGrow</enum> + </property> + <item row="0" column="0"> + <widget class="QLabel" name="updateChannelLabel"> + <property name="text"> + <string>Basic.Settings.General.UpdateChannel</string> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QComboBox" name="updateChannelBox"> + <property name="editable"> + <bool>false</bool> + </property> + <property name="currentText"> + <string/> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QCheckBox" name="enableAutoUpdates"> + <property name="text"> + <string>Basic.Settings.General.EnableAutoUpdates</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + </widget> + </item> + <item row="1" column="0"> + <spacer name="horizontalSpacer_29"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Fixed</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>170</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + </layout> + </widget> + </item> + <item> <widget class="QGroupBox" name="groupBox_16"> <property name="title"> <string>Basic.Settings.Output</string> @@ -7473,6 +7521,7 @@ <tabstop>scrollArea_2</tabstop> <tabstop>language</tabstop> <tabstop>theme</tabstop> + <tabstop>updateChannelBox</tabstop> <tabstop>enableAutoUpdates</tabstop> <tabstop>openStatsOnStartup</tabstop> <tabstop>warnBeforeStreamStart</tabstop> @@ -7615,7 +7664,6 @@ <tabstop>colorSpace</tabstop> <tabstop>colorRange</tabstop> <tabstop>sdrWhiteLevel</tabstop> - <tabstop>horizontalLayout_sdrPaperWhite</tabstop> <tabstop>hdrNominalPeakLevel</tabstop> <tabstop>disableOSXVSync</tabstop> <tabstop>resetOSXVSync</tabstop>
View file
obs-studio-28.1.2.tar.xz/UI/frontend-plugins/decklink-output-ui/decklink-ui-main.cpp -> obs-studio-29.0.0.tar.xz/UI/frontend-plugins/decklink-output-ui/decklink-ui-main.cpp
Changed
@@ -21,6 +21,8 @@ obs_output_t *output; +constexpr size_t STAGE_BUFFER_COUNT = 3; + struct preview_output { bool enabled; obs_source_t *current_source; @@ -28,7 +30,9 @@ video_t *video_queue; gs_texrender_t *texrender; - gs_stagesurf_t *stagesurface; + gs_stagesurf_t *stagesurfacesSTAGE_BUFFER_COUNT; + bool surf_writtenSTAGE_BUFFER_COUNT; + size_t stage_index; uint8_t *video_data; uint32_t video_linesize; @@ -131,7 +135,8 @@ obs_source_release(context.current_source); obs_enter_graphics(); - gs_stagesurface_destroy(context.stagesurface); + for (gs_stagesurf_t *surf : context.stagesurfaces) + gs_stagesurface_destroy(surf); gs_texrender_destroy(context.texrender); obs_leave_graphics(); @@ -161,10 +166,15 @@ obs_enter_graphics(); context.texrender = gs_texrender_create(GS_BGRA, GS_ZS_NONE); - context.stagesurface = - gs_stagesurface_create(width, height, GS_BGRA); + for (gs_stagesurf_t *&surf : context.stagesurfaces) + surf = gs_stagesurface_create(width, height, GS_BGRA); obs_leave_graphics(); + for (bool &written : context.surf_written) + written = false; + + context.stage_index = 0; + const video_output_info *mainVOI = video_output_get_info(obs_get_video()); @@ -266,34 +276,47 @@ gs_blend_state_pop(); gs_texrender_end(ctx->texrender); - struct video_frame output_frame; - if (video_output_lock_frame(ctx->video_queue, &output_frame, 1, - os_gettime_ns())) { - gs_stage_texture( - ctx->stagesurface, - gs_texrender_get_texture(ctx->texrender)); - - if (gs_stagesurface_map(ctx->stagesurface, - &ctx->video_data, - &ctx->video_linesize)) { - uint32_t linesize = output_frame.linesize0; - for (uint32_t i = 0; i < ctx->ovi.base_height; - i++) { - uint32_t dst_offset = linesize * i; - uint32_t src_offset = - ctx->video_linesize * i; - memcpy(output_frame.data0 + - dst_offset, - ctx->video_data + src_offset, - linesize); + const size_t write_stage_index = ctx->stage_index; + gs_stage_texture(ctx->stagesurfaceswrite_stage_index, + gs_texrender_get_texture(ctx->texrender)); + ctx->surf_writtenwrite_stage_index = true; + + const size_t read_stage_index = + (write_stage_index + 1) % STAGE_BUFFER_COUNT; + if (ctx->surf_writtenread_stage_index) { + struct video_frame output_frame; + if (video_output_lock_frame(ctx->video_queue, + &output_frame, 1, + os_gettime_ns())) { + gs_stagesurf_t *const read_surf = + ctx->stagesurfacesread_stage_index; + if (gs_stagesurface_map(read_surf, + &ctx->video_data, + &ctx->video_linesize)) { + uint32_t linesize = + output_frame.linesize0; + for (uint32_t i = 0; + i < ctx->ovi.base_height; i++) { + uint32_t dst_offset = + linesize * i; + uint32_t src_offset = + ctx->video_linesize * i; + memcpy(output_frame.data0 + + dst_offset, + ctx->video_data + + src_offset, + linesize); + } + + gs_stagesurface_unmap(read_surf); + ctx->video_data = nullptr; } - gs_stagesurface_unmap(ctx->stagesurface); - ctx->video_data = nullptr; + video_output_unlock_frame(ctx->video_queue); } - - video_output_unlock_frame(ctx->video_queue); } + + ctx->stage_index = read_stage_index; } }
View file
obs-studio-28.1.2.tar.xz/UI/frontend-plugins/decklink-output-ui/forms/output.ui -> obs-studio-29.0.0.tar.xz/UI/frontend-plugins/decklink-output-ui/forms/output.ui
Changed
@@ -122,7 +122,7 @@ <item> <widget class="QLabel" name="keyerLabel"> <property name="text"> - <string>Keyer output requires RGB mode in advanced settings.</string> + <string>Keyer output requires BGRA mode in advanced settings.</string> </property> </widget> </item>
View file
obs-studio-28.1.2.tar.xz/UI/media-controls.cpp -> obs-studio-29.0.0.tar.xz/UI/media-controls.cpp
Changed
@@ -31,6 +31,18 @@ QMetaObject::invokeMethod(media, "SetPlayingState"); } +void MediaControls::OBSMediaNext(void *data, calldata_t *) +{ + MediaControls *media = static_cast<MediaControls *>(data); + QMetaObject::invokeMethod(media, "UpdateSlideCounter"); +} + +void MediaControls::OBSMediaPrevious(void *data, calldata_t *) +{ + MediaControls *media = static_cast<MediaControls *>(data); + QMetaObject::invokeMethod(media, "UpdateSlideCounter"); +} + MediaControls::MediaControls(QWidget *parent) : QWidget(parent), ui(new Ui::MediaControls) { @@ -196,6 +208,7 @@ prevPaused = false; + UpdateSlideCounter(); StartMediaTimer(); } @@ -219,8 +232,15 @@ QTStr("ContextBar.MediaControls.RestartMedia")); ui->slider->setValue(0); - ui->timerLabel->setText("--:--:--"); - ui->durationLabel->setText("--:--:--"); + + if (!isSlideshow) { + ui->timerLabel->setText("--:--:--"); + ui->durationLabel->setText("--:--:--"); + } else { + ui->timerLabel->setText("-"); + ui->durationLabel->setText("-"); + } + ui->slider->setEnabled(false); StopMediaTimer(); @@ -255,9 +275,6 @@ isSlideshow = strcmp(id, "slideshow") == 0; ui->slider->setVisible(!isSlideshow); - ui->timerLabel->setVisible(!isSlideshow); - ui->label->setVisible(!isSlideshow); - ui->durationLabel->setVisible(!isSlideshow); ui->emptySpaceAgain->setVisible(isSlideshow); obs_media_state state = obs_source_media_get_state(source); @@ -278,7 +295,10 @@ break; } - SetSliderPosition(); + if (isSlideshow) + UpdateSlideCounter(); + else + SetSliderPosition(); } OBSSource MediaControls::GetSource() @@ -299,6 +319,8 @@ sigs.emplace_back(sh, "media_stopped", OBSMediaStopped, this); sigs.emplace_back(sh, "media_started", OBSMediaStarted, this); sigs.emplace_back(sh, "media_ended", OBSMediaStopped, this); + sigs.emplace_back(sh, "media_next", OBSMediaNext, this); + sigs.emplace_back(sh, "media_previous", OBSMediaPrevious, this); } else { weakSource = nullptr; } @@ -467,3 +489,32 @@ obs_source_media_set_time(source, ms); SetSliderPosition(); } + +void MediaControls::UpdateSlideCounter() +{ + if (!isSlideshow) + return; + + OBSSource source = OBSGetStrongRef(weakSource); + + if (!source) + return; + + proc_handler_t *ph = obs_source_get_proc_handler(source); + calldata_t cd = {}; + + proc_handler_call(ph, "current_index", &cd); + int slide = calldata_int(&cd, "current_index"); + + proc_handler_call(ph, "total_files", &cd); + int total = calldata_int(&cd, "total_files"); + calldata_free(&cd); + + if (total > 0) { + ui->timerLabel->setText(QString::number(slide + 1)); + ui->durationLabel->setText(QString::number(total)); + } else { + ui->timerLabel->setText("-"); + ui->durationLabel->setText("-"); + } +}
View file
obs-studio-28.1.2.tar.xz/UI/media-controls.hpp -> obs-studio-29.0.0.tar.xz/UI/media-controls.hpp
Changed
@@ -33,6 +33,8 @@ static void OBSMediaPlay(void *data, calldata_t *calldata); static void OBSMediaPause(void *data, calldata_t *calldata); static void OBSMediaStarted(void *data, calldata_t *calldata); + static void OBSMediaNext(void *data, calldata_t *calldata); + static void OBSMediaPrevious(void *data, calldata_t *calldata); std::unique_ptr<Ui_MediaControls> ui; @@ -61,6 +63,8 @@ void MoveSliderFoward(int seconds = 5); void MoveSliderBackwards(int seconds = 5); + void UpdateSlideCounter(); + public slots: void PlayMedia(); void PauseMedia();
View file
obs-studio-28.1.2.tar.xz/UI/multiview.cpp -> obs-studio-29.0.0.tar.xz/UI/multiview.cpp
Changed
@@ -174,9 +174,8 @@ multiviewScenes.emplace_back(OBSGetWeakRef(src)); obs_source_inc_showing(src); - std::string name = std::to_string(numSrcs) + " - " + - obs_source_get_name(src); - multiviewLabels.emplace_back(CreateLabel(name.c_str(), h / 3)); + multiviewLabels.emplace_back( + CreateLabel(obs_source_get_name(src), h / 3)); } obs_frontend_source_list_free(&scenes);
View file
obs-studio-28.1.2.tar.xz/UI/obs-app.cpp -> obs-studio-29.0.0.tar.xz/UI/obs-app.cpp
Changed
@@ -55,6 +55,7 @@ #include <curl/curl.h> #ifdef _WIN32 +#include <json11.hpp> #include <windows.h> #include <filesystem> #else @@ -376,7 +377,7 @@ va_copy(args2, args); #endif - vsnprintf(str, 4095, msg, args); + vsnprintf(str, sizeof(str), msg, args); #ifdef _WIN32 if (IsDebuggerPresent()) { @@ -1264,6 +1265,112 @@ return SetTheme("System"); } +#ifdef _WIN32 +void ParseBranchesJson(const std::string &jsonString, vector<UpdateBranch> &out, + std::string &error) +{ + json11::Json root; + root = json11::Json::parse(jsonString, error); + if (!error.empty() || !root.is_array()) + return; + + for (const json11::Json &item : root.array_items()) { +#ifdef _WIN32 + if (!item"windows".bool_value()) + continue; +#endif + + UpdateBranch branch = { + QString::fromStdString(item"name".string_value()), + QString::fromStdString( + item"display_name".string_value()), + QString::fromStdString( + item"description".string_value()), + item"enabled".bool_value(), + item"visible".bool_value(), + }; + out.push_back(branch); + } +} + +bool LoadBranchesFile(vector<UpdateBranch> &out) +{ + string error; + string branchesText; + + BPtr<char> branchesFilePath = + GetConfigPathPtr("obs-studio/updates/branches.json"); + + QFile branchesFile(branchesFilePath.Get()); + if (!branchesFile.open(QIODevice::ReadOnly)) { + error = "Opening file failed."; + goto fail; + } + + branchesText = branchesFile.readAll(); + if (branchesText.empty()) { + error = "File empty."; + goto fail; + } + + ParseBranchesJson(branchesText, out, error); + if (error.empty()) + return !out.empty(); + +fail: + blog(LOG_WARNING, "Loading branches from file failed: %s", + error.c_str()); + return false; +} +#endif + +void OBSApp::SetBranchData(const string &data) +{ +#ifdef _WIN32 + string error; + vector<UpdateBranch> result; + + ParseBranchesJson(data, result, error); + + if (!error.empty()) { + blog(LOG_WARNING, "Reading branches JSON response failed: %s", + error.c_str()); + return; + } + + if (!result.empty()) + updateBranches = result; + + branches_loaded = true; +#else + UNUSED_PARAMETER(data); +#endif +} + +std::vector<UpdateBranch> OBSApp::GetBranches() +{ + vector<UpdateBranch> out; + /* Always ensure the default branch exists */ + out.push_back(UpdateBranch{"stable", "", "", true, true}); + +#ifdef _WIN32 + if (!branches_loaded) { + vector<UpdateBranch> result; + if (LoadBranchesFile(result)) + updateBranches = result; + + branches_loaded = true; + } +#endif + + /* Copy additional branches to result (if any) */ + if (!updateBranches.empty()) + out.insert(out.end(), updateBranches.begin(), + updateBranches.end()); + + return out; +} + OBSApp::OBSApp(int &argc, char **argv, profiler_name_store_t *store) : QApplication(argc, argv), profilerNameStore(store) { @@ -2199,10 +2306,12 @@ /* NOTE: Qt doesn't use the Wayland platform on GNOME, so we have to * force it using the QT_QPA_PLATFORM env var. It's still possible to * use other QPA platforms using this env var, or the -platform command - * line option. */ + * line option. Remove after Qt 6.3 is everywhere. */ + const char *desktop = getenv("XDG_CURRENT_DESKTOP"); const char *session_type = getenv("XDG_SESSION_TYPE"); - if (session_type && strcmp(session_type, "wayland") == 0) + if (session_type && desktop && strcmp(desktop, "GNOME") == 0 && + strcmp(session_type, "wayland") == 0) setenv("QT_QPA_PLATFORM", "wayland", false); #endif #endif @@ -2316,10 +2425,6 @@ audio_permission, accessibility_permission); check->exec(); } - - bool rosettaTranslated = os_get_emulation_status(); - blog(LOG_INFO, "Rosetta translation used: %s", - rosettaTranslated ? "true" : "false"); #endif #ifdef _WIN32 @@ -2662,16 +2767,16 @@ if (!home) return; - if (snprintf(old_path, 512, "%s/.obs-studio", home) <= 0) + if (snprintf(old_path, sizeof(old_path), "%s/.obs-studio", home) <= 0) return; /* make base xdg path if it doesn't already exist */ - if (GetConfigPath(new_path, 512, "") <= 0) + if (GetConfigPath(new_path, sizeof(new_path), "") <= 0) return; if (os_mkdirs(new_path) == MKDIR_ERROR) return; - if (GetConfigPath(new_path, 512, "obs-studio") <= 0) + if (GetConfigPath(new_path, sizeof(new_path), "obs-studio") <= 0) return; if (os_file_exists(old_path) && !os_file_exists(new_path)) {
View file
obs-studio-28.1.2.tar.xz/UI/obs-app.hpp -> obs-studio-29.0.0.tar.xz/UI/obs-app.hpp
Changed
@@ -74,6 +74,14 @@ std::string author; }; +struct UpdateBranch { + QString name; + QString display_name; + QString description; + bool is_enabled; + bool is_visible; +}; + class OBSApp : public QApplication { Q_OBJECT @@ -86,6 +94,8 @@ TextLookup textLookup; QPointer<OBSMainWindow> mainWindow; profiler_name_store_t *profilerNameStore = nullptr; + std::vector<UpdateBranch> updateBranches; + bool branches_loaded = false; bool libobs_initialized = false; @@ -142,6 +152,9 @@ bool SetTheme(std::string name, std::string path = ""); inline bool IsThemeDark() const { return themeDarkMode; }; + void SetBranchData(const std::string &data); + std::vector<UpdateBranch> GetBranches(); + inline lookup_t *GetTextLookup() const { return textLookup; } inline const char *GetString(const char *lookupVal) const
View file
obs-studio-28.1.2.tar.xz/UI/obs-frontend-api/obs-frontend-api.cpp -> obs-studio-29.0.0.tar.xz/UI/obs-frontend-api/obs-frontend-api.cpp
Changed
@@ -571,3 +571,26 @@ return !!callbacks_valid() ? c->obs_frontend_get_locale_string(string) : nullptr; } + +bool obs_frontend_is_theme_dark(void) +{ + return !!callbacks_valid() ? c->obs_frontend_is_theme_dark() : false; +} + +char *obs_frontend_get_last_recording(void) +{ + return !!callbacks_valid() ? c->obs_frontend_get_last_recording() + : nullptr; +} + +char *obs_frontend_get_last_screenshot(void) +{ + return !!callbacks_valid() ? c->obs_frontend_get_last_screenshot() + : nullptr; +} + +char *obs_frontend_get_last_replay(void) +{ + return !!callbacks_valid() ? c->obs_frontend_get_last_replay() + : nullptr; +}
View file
obs-studio-28.1.2.tar.xz/UI/obs-frontend-api/obs-frontend-api.h -> obs-studio-29.0.0.tar.xz/UI/obs-frontend-api/obs-frontend-api.h
Changed
@@ -60,6 +60,8 @@ OBS_FRONTEND_EVENT_SCRIPTING_SHUTDOWN, OBS_FRONTEND_EVENT_PROFILE_RENAMED, OBS_FRONTEND_EVENT_SCENE_COLLECTION_RENAMED, + OBS_FRONTEND_EVENT_THEME_CHANGED, + OBS_FRONTEND_EVENT_SCREENSHOT_TAKEN, }; /* ------------------------------------------------------------------------- */ @@ -228,6 +230,12 @@ EXPORT char *obs_frontend_get_current_record_output_path(void); EXPORT const char *obs_frontend_get_locale_string(const char *string); +EXPORT bool obs_frontend_is_theme_dark(void); + +EXPORT char *obs_frontend_get_last_recording(void); +EXPORT char *obs_frontend_get_last_screenshot(void); +EXPORT char *obs_frontend_get_last_replay(void); + /* ------------------------------------------------------------------------- */ #ifdef __cplusplus
View file
obs-studio-28.1.2.tar.xz/UI/obs-frontend-api/obs-frontend-internal.hpp -> obs-studio-29.0.0.tar.xz/UI/obs-frontend-api/obs-frontend-internal.hpp
Changed
@@ -145,6 +145,12 @@ virtual char *obs_frontend_get_current_record_output_path(void) = 0; virtual const char * obs_frontend_get_locale_string(const char *string) = 0; + + virtual bool obs_frontend_is_theme_dark(void) = 0; + + virtual char *obs_frontend_get_last_recording(void) = 0; + virtual char *obs_frontend_get_last_screenshot(void) = 0; + virtual char *obs_frontend_get_last_replay(void) = 0; }; EXPORT void
View file
obs-studio-28.1.2.tar.xz/UI/platform-windows.cpp -> obs-studio-29.0.0.tar.xz/UI/platform-windows.cpp
Changed
@@ -37,11 +37,6 @@ #include <util/windows/HRError.hpp> #include <util/windows/ComPtr.hpp> -#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) -#include <QWinTaskbarButton> -#include <QMainWindow> -#endif - using namespace std; static inline bool check_path(const char *data, const char *path, @@ -51,7 +46,7 @@ str << path << data; output = str.str(); - printf("Attempted path: %s\n", output.c_str()); + blog(LOG_DEBUG, "Attempted path: %s", output.c_str()); return os_file_exists(output.c_str()); } @@ -176,33 +171,6 @@ return build; } -void SetAeroEnabled(bool enable) -{ - static HRESULT(WINAPI * func)(UINT) = nullptr; - static bool failed = false; - - if (!func) { - if (failed) { - return; - } - - HMODULE dwm = LoadLibraryW(L"dwmapi"); - if (!dwm) { - failed = true; - return; - } - - func = reinterpret_cast<decltype(func)>( - GetProcAddress(dwm, "DwmEnableComposition")); - if (!func) { - failed = true; - return; - } - } - - func(enable ? DWM_EC_ENABLECOMPOSITION : DWM_EC_DISABLECOMPOSITION); -} - bool IsAlwaysOnTop(QWidget *window) { DWORD exStyle = GetWindowLong((HWND)window->winId(), GWL_EXSTYLE); @@ -388,6 +356,7 @@ return true; } +#if QT_VERSION < QT_VERSION_CHECK(6, 4, 0) #define GENERIC_MONITOR_NAME QStringLiteral("Generic PnP Monitor") QString GetMonitorName(const QString &id) @@ -449,6 +418,7 @@ return QString::fromWCharArray(target.monitorFriendlyDeviceName); } +#endif /* Based on https://www.winehq.org/pipermail/wine-devel/2008-September/069387.html */ typedef const char *(CDECL *WINEGETVERSION)(void); @@ -470,35 +440,6 @@ return false; } -#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) -QWinTaskbarButton *taskBtn; - -void TaskbarOverlayInit() -{ - QMainWindow *main = App()->GetMainWindow(); - taskBtn = new QWinTaskbarButton(main); - taskBtn->setWindow(main->windowHandle()); -} - -void TaskbarOverlaySetStatus(TaskbarOverlayStatus status) -{ - if (status == TaskbarOverlayStatusInactive) { - taskBtn->clearOverlayIcon(); - return; - } - - QIcon icon; - if (status == TaskbarOverlayStatusActive) { - icon = QIcon::fromTheme("obs-active", - QIcon(":/res/images/active.png")); - } else { - icon = QIcon::fromTheme("obs-paused", - QIcon(":/res/images/paused.png")); - } - taskBtn->setOverlayIcon(icon); -} -#else - HWND hwnd; void TaskbarOverlayInit() { @@ -554,4 +495,3 @@ } taskbarIcon->Release(); } -#endif
View file
obs-studio-28.1.2.tar.xz/UI/platform-x11.cpp -> obs-studio-29.0.0.tar.xz/UI/platform-x11.cpp
Changed
@@ -178,7 +178,7 @@ str << path << data; output = str.str(); - printf("Attempted path: %s\n", output.c_str()); + blog(LOG_DEBUG, "Attempted path: %s", output.c_str()); return (access(output.c_str(), R_OK) == 0); }
View file
obs-studio-28.1.2.tar.xz/UI/platform.hpp -> obs-studio-29.0.0.tar.xz/UI/platform.hpp
Changed
@@ -55,7 +55,6 @@ #ifdef _WIN32 uint32_t GetWindowsVersion(); uint32_t GetWindowsBuild(); -void SetAeroEnabled(bool enable); void SetProcessPriority(const char *priority); void SetWin32DropStyle(QWidget *window); bool DisableAudioDucking(bool disable); @@ -75,7 +74,9 @@ RunOnceMutex &operator=(RunOnceMutex &&rom); }; +#if QT_VERSION < QT_VERSION_CHECK(6, 4, 0) QString GetMonitorName(const QString &id); +#endif bool IsRunningOnWine(); #endif
View file
obs-studio-28.1.2.tar.xz/UI/qt-wrappers.cpp -> obs-studio-29.0.0.tar.xz/UI/qt-wrappers.cpp
Changed
@@ -30,6 +30,7 @@ #include <QStandardItemModel> #include <QLabel> #include <QPushButton> +#include <QToolBar> #if !defined(_WIN32) && !defined(__APPLE__) #include <obs-nix-platform.h> @@ -42,7 +43,7 @@ static inline void OBSErrorBoxva(QWidget *parent, const char *msg, va_list args) { char full_message4096; - vsnprintf(full_message, 4095, msg, args); + vsnprintf(full_message, sizeof(full_message), msg, args); QMessageBox::critical(parent, "Error", full_message); } @@ -406,3 +407,12 @@ SetLabelText(label, newText); } + +void RefreshToolBarStyling(QToolBar *toolBar) +{ + for (QAction *action : toolBar->actions()) { + QWidget *widget = toolBar->widgetForAction(action); + widget->style()->unpolish(widget); + widget->style()->polish(widget); + } +}
View file
obs-studio-28.1.2.tar.xz/UI/qt-wrappers.hpp -> obs-studio-29.0.0.tar.xz/UI/qt-wrappers.hpp
Changed
@@ -39,6 +39,7 @@ class QString; struct gs_window; class QLabel; +class QToolBar; class OBSMessageBox { public: @@ -122,3 +123,5 @@ void TruncateLabel(QLabel *label, QString newText, int length = MAX_LABEL_LENGTH); + +void RefreshToolBarStyling(QToolBar *toolBar);
View file
obs-studio-28.1.2.tar.xz/UI/volume-control.cpp -> obs-studio-29.0.0.tar.xz/UI/volume-control.cpp
Changed
@@ -204,6 +204,7 @@ volMeter = new VolumeMeter(nullptr, obs_volmeter, true); slider = new VolumeSlider(obs_fader, Qt::Vertical); + slider->setLayoutDirection(Qt::LeftToRight); nameLayout->setAlignment(Qt::AlignCenter); meterLayout->setAlignment(Qt::AlignCenter); @@ -253,6 +254,7 @@ volMeter = new VolumeMeter(nullptr, obs_volmeter, false); slider = new VolumeSlider(obs_fader, Qt::Horizontal); + slider->setLayoutDirection(Qt::LeftToRight); textLayout->setContentsMargins(0, 0, 0, 0); textLayout->addWidget(nameLabel);
View file
obs-studio-28.1.2.tar.xz/UI/win-update/updater/http.cpp -> obs-studio-29.0.0.tar.xz/UI/win-update/updater/http.cpp
Changed
@@ -125,7 +125,7 @@ /* -------------------------------------- * * connect to server */ - hSession = WinHttpOpen(L"OBS Studio Updater/2.1", + hSession = WinHttpOpen(L"OBS Studio Updater/2.2", WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0);
View file
obs-studio-28.1.2.tar.xz/UI/win-update/updater/updater.cpp -> obs-studio-29.0.0.tar.xz/UI/win-update/updater/updater.cpp
Changed
@@ -376,7 +376,7 @@ const DWORD enableHTTP2Flag = WINHTTP_PROTOCOL_FLAG_HTTP2; - HttpHandle hSession = WinHttpOpen(L"OBS Studio Updater/2.1", + HttpHandle hSession = WinHttpOpen(L"OBS Studio Updater/2.2", WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0); @@ -652,7 +652,8 @@ #define UPDATE_URL L"https://cdn-fastly.obsproject.com/update_studio" static bool AddPackageUpdateFiles(const Json &root, size_t idx, - const wchar_t *tempPath) + const wchar_t *tempPath, + const wchar_t *branch) { const Json &package = rootidx; const Json &name = package"name"; @@ -726,8 +727,9 @@ return false; } - StringCbPrintf(sourceURL, sizeof(sourceURL), L"%s/%s/%s", - UPDATE_URL, wPackageName, updateFileName); + StringCbPrintf(sourceURL, sizeof(sourceURL), L"%s/%s/%s/%s", + UPDATE_URL, branch, wPackageName, + updateFileName); StringCbPrintf(tempFilePath, sizeof(tempFilePath), L"%s\\%s", tempPath, updateHashStr); @@ -1092,7 +1094,7 @@ const DWORD tlsProtocols = WINHTTP_FLAG_SECURE_PROTOCOL_TLS1_2; - HttpHandle hSession = WinHttpOpen(L"OBS Studio Updater/2.1", + HttpHandle hSession = WinHttpOpen(L"OBS Studio Updater/2.2", WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0); @@ -1284,6 +1286,7 @@ * Check if updating portable build */ bool bIsPortable = false; + wstring branch = L"stable"; if (cmdLine0) { int argc; @@ -1292,10 +1295,17 @@ if (argv) { for (int i = 0; i < argc; i++) { if (wcscmp(argvi, L"Portable") == 0) { + // Legacy OBS + bIsPortable = true; + break; + } else if (wcsncmp(argvi, L"--branch=", 9) == + 0) { + branch = argvi + 9; + } else if (wcscmp(argvi, L"--portable") == + 0) { bIsPortable = true; } } - LocalFree((HLOCAL)argv); } } @@ -1396,7 +1406,8 @@ const Json::array &packages = root"packages".array_items(); for (size_t i = 0; i < packages.size(); i++) { - if (!AddPackageUpdateFiles(packages, i, tempPath)) { + if (!AddPackageUpdateFiles(packages, i, tempPath, + branch.c_str())) { Status(L"Update failed: Failed to process update packages"); return false; } @@ -1481,7 +1492,11 @@ Z_BEST_COMPRESSION); compressedJson.resize(compressSize); - bool success = !!HTTPPostData(PATCH_MANIFEST_URL, + wstring manifestUrl(PATCH_MANIFEST_URL); + if (branch != L"stable") + manifestUrl += L"?branch=" + branch; + + bool success = !!HTTPPostData(manifestUrl.c_str(), (BYTE *)&compressedJson0, (int)compressedJson.size(), L"Accept-Encoding: gzip",
View file
obs-studio-28.1.2.tar.xz/UI/win-update/win-update.cpp -> obs-studio-29.0.0.tar.xz/UI/win-update/win-update.cpp
Changed
@@ -36,6 +36,18 @@ #define WIN_MANIFEST_URL "https://obsproject.com/update_studio/manifest.json" #endif +#ifndef WIN_MANIFEST_BASE_URL +#define WIN_MANIFEST_BASE_URL "https://obsproject.com/update_studio/" +#endif + +#ifndef WIN_BRANCHES_URL +#define WIN_BRANCHES_URL "https://obsproject.com/update_studio/branches.json" +#endif + +#ifndef WIN_DEFAULT_BRANCH +#define WIN_DEFAULT_BRANCH "stable" +#endif + #ifndef WIN_WHATSNEW_URL #define WIN_WHATSNEW_URL "https://obsproject.com/update_studio/whatsnew.json" #endif @@ -399,8 +411,30 @@ /* ------------------------------------------------------------------------ */ +#if defined(OBS_RELEASE_CANDIDATE) && OBS_RELEASE_CANDIDATE > 0 +#define CUR_VER \ + ((uint64_t)OBS_RELEASE_CANDIDATE_VER << 16ULL | OBS_RELEASE_CANDIDATE \ + << 8ULL) +#define PRE_RELEASE true +#elif OBS_BETA > 0 +#define CUR_VER ((uint64_t)OBS_BETA_VER << 16ULL | OBS_BETA) +#define PRE_RELEASE true +#elif defined(OBS_COMMIT) +#define CUR_VER 1 << 16ULL +#define CUR_COMMIT OBS_COMMIT +#define PRE_RELEASE true +#else +#define CUR_VER ((uint64_t)LIBOBS_API_VER << 16ULL) +#define PRE_RELEASE false +#endif + +#ifndef CUR_COMMIT +#define CUR_COMMIT "00000000" +#endif + static bool ParseUpdateManifest(const char *manifest, bool *updatesAvailable, - string ¬es_str, int &updateVer) + string ¬es_str, uint64_t &updateVer, + string &branch) try { string error; @@ -415,8 +449,11 @@ int major = root"version_major".int_value(); int minor = root"version_minor".int_value(); int patch = root"version_patch".int_value(); + int rc = root"rc".int_value(); + int beta = root"beta".int_value(); + string commit_hash = root"commit".string_value(); - if (major == 0) + if (major == 0 && commit_hash.empty()) throw strprintf("Invalid version number: %d.%d.%d", major, minor, patch); @@ -430,11 +467,35 @@ if (!packages.is_array()) throw string("'packages' value invalid"); - int cur_ver = LIBOBS_API_VER; - int new_ver = MAKE_SEMANTIC_VERSION(major, minor, patch); + uint64_t cur_ver; + uint64_t new_ver; + + if (commit_hash.empty()) { + cur_ver = CUR_VER; + new_ver = MAKE_SEMANTIC_VERSION( + (uint64_t)major, (uint64_t)minor, (uint64_t)patch); + new_ver <<= 16; + /* RC builds are shifted so that rc1 and beta1 versions do not result + * in the same new_ver. */ + if (rc > 0) + new_ver |= (uint64_t)rc << 8; + else if (beta > 0) + new_ver |= (uint64_t)beta; + } else { + /* Test or nightly builds may not have a (valid) version number, + * so compare commit hashes instead. */ + cur_ver = stoul(CUR_COMMIT, nullptr, 16); + new_ver = stoul(commit_hash.substr(0, 8), nullptr, 16); + } updateVer = new_ver; - *updatesAvailable = new_ver > cur_ver; + + /* When using a pre-release build or non-default branch we only check if + * the manifest version is different, so that it can be rolled-back. */ + if (branch != WIN_DEFAULT_BRANCH || PRE_RELEASE) + *updatesAvailable = new_ver != cur_ver; + else + *updatesAvailable = new_ver > cur_ver; return true; @@ -443,6 +504,10 @@ return false; } +#undef CUR_COMMIT +#undef CUR_VER +#undef PRE_RELEASE + /* ------------------------------------------------------------------------ */ void GenerateGUID(string &guid) @@ -481,6 +546,127 @@ return guid; } +/* ------------------------------------------------------------------------ */ + +bool GetBranchAndUrl(string &selectedBranch, string &manifestUrl) +{ + const char *config_branch = + config_get_string(GetGlobalConfig(), "General", "UpdateBranch"); + if (!config_branch) + return true; + + bool found = false; + for (const UpdateBranch &branch : App()->GetBranches()) { + if (branch.name != config_branch) + continue; + /* A branch that is found but disabled will just silently fall back to + * the default. But if the branch was removed entirely, the user should + * be warned, so leave this false *only* if the branch was removed. */ + found = true; + + if (branch.is_enabled) { + selectedBranch = branch.name.toStdString(); + if (branch.name != WIN_DEFAULT_BRANCH) { + manifestUrl = WIN_MANIFEST_BASE_URL; + manifestUrl += "manifest_" + + branch.name.toStdString() + + ".json"; + } + } + break; + } + + return found; +} + +/* ------------------------------------------------------------------------ */ + +static bool +FetchAndVerifyFile(const char *name, const char *file, const char *url, + string &text, + const vector<string> &extraHeaders = vector<string>()) +{ + long responseCode; + vector<string> headers; + string error; + string signature; + BYTE fileHashBLAKE2_HASH_LENGTH; + bool success; + + BPtr<char> filePath = GetConfigPathPtr(file); + + if (!extraHeaders.empty()) { + headers.insert(headers.end(), extraHeaders.begin(), + extraHeaders.end()); + } + + /* ----------------------------------- * + * avoid downloading json again */ + + if (CalculateFileHash(filePath, fileHash)) { + char hashStringBLAKE2_HASH_STR_LENGTH; + HashToString(fileHash, hashString); + + string header = "If-None-Match: "; + header += hashString; + headers.push_back(move(header)); + } + + /* ----------------------------------- * + * get current install GUID */ + + string guid = GetProgramGUID(); + + if (!guid.empty()) { + string header = "X-OBS2-GUID: "; + header += guid; + headers.push_back(move(header)); + } + + /* ----------------------------------- * + * get json from server */ + + success = GetRemoteFile(url, text, error, &responseCode, nullptr, "", + nullptr, headers, &signature); + + if (!success || (responseCode != 200 && responseCode != 304)) { + if (responseCode == 404) + return false; + + throw strprintf("Failed to fetch %s file: %s", name, + error.c_str()); + } + + /* ----------------------------------- * + * verify file signature */ + + if (responseCode == 200) { + success = CheckDataSignature(text, name, signature.data(), + signature.size()); + if (!success) + throw strprintf("Invalid %s signature", name); + } + + /* ----------------------------------- * + * write or load json */ + + if (responseCode == 200) { + if (!QuickWriteFile(filePath, text.data(), text.size())) + throw strprintf("Could not write file '%s'", + filePath.Get()); + } else { + if (!QuickReadFile(filePath, text)) + throw strprintf("Could not read file '%s'", + filePath.Get()); + } + + /* ----------------------------------- * + * success */ + return true; +} + +/* ------------------------------------------------------------------------ */ + void AutoUpdateThread::infoMsg(const QString &title, const QString &text) { OBSMessageBox::information(App()->GetMainWindow(), title, text); @@ -532,15 +718,12 @@ void AutoUpdateThread::run() try { - long responseCode; - vector<string> extraHeaders; string text; - string error; - string signature; - CryptProvider localProvider; - BYTE manifestHashBLAKE2_HASH_LENGTH; + string branch = WIN_DEFAULT_BRANCH; + string manifestUrl = WIN_MANIFEST_URL; + vector<string> extraHeaders; bool updatesAvailable = false; - bool success; + CryptProvider localProvider; struct FinishedTrigger { inline ~FinishedTrigger() @@ -550,9 +733,6 @@ } } finishedTrigger; - BPtr<char> manifestPath = - GetConfigPathPtr("obs-studio\\updates\\manifest.json"); - /* ----------------------------------- * * create signature provider */ @@ -564,25 +744,20 @@ provider = localProvider; /* ----------------------------------- * - * avoid downloading manifest again */ + * get branches from server */ - if (CalculateFileHash(manifestPath, manifestHash)) { - char hashStringBLAKE2_HASH_STR_LENGTH; - HashToString(manifestHash, hashString); - - string header = "If-None-Match: "; - header += hashString; - extraHeaders.push_back(move(header)); - } + if (FetchAndVerifyFile("branches", "obs-studio\\updates\\branches.json", + WIN_BRANCHES_URL, text)) + App()->SetBranchData(text); /* ----------------------------------- * - * get current install GUID */ + * get branches from server */ - string guid = GetProgramGUID(); - if (!guid.empty()) { - string header = "X-OBS2-GUID: "; - header += guid; - extraHeaders.push_back(move(header)); + if (!GetBranchAndUrl(branch, manifestUrl)) { + config_set_string(GetGlobalConfig(), "General", "UpdateBranch", + WIN_DEFAULT_BRANCH); + info(QTStr("Updater.BranchNotFound.Title"), + QTStr("Updater.BranchNotFound.Text")); } /* allow server to know if this was a manual update check in case @@ -593,50 +768,20 @@ /* ----------------------------------- * * get manifest from server */ - success = GetRemoteFile(WIN_MANIFEST_URL, text, error, &responseCode, - nullptr, "", nullptr, extraHeaders, &signature); - - if (!success || (responseCode != 200 && responseCode != 304)) { - if (responseCode == 404) - return; - - throw strprintf("Failed to fetch manifest file: %s", - error.c_str()); - } - - /* ----------------------------------- * - * verify file signature */ - - /* a new file must be digitally signed */ - if (responseCode == 200) { - success = CheckDataSignature(text, "manifest", signature.data(), - signature.size()); - if (!success) - throw string("Invalid manifest signature"); - } - - /* ----------------------------------- * - * write or load manifest */ - - if (responseCode == 200) { - if (!QuickWriteFile(manifestPath, text.data(), text.size())) - throw strprintf("Could not write file '%s'", - manifestPath.Get()); - } else { - if (!QuickReadFile(manifestPath, text)) - throw strprintf("Could not read file '%s'", - manifestPath.Get()); - } + text.clear(); + if (!FetchAndVerifyFile("manifest", + "obs-studio\\updates\\manifest.json", + manifestUrl.c_str(), text, extraHeaders)) + return; /* ----------------------------------- * * check manifest for update */ string notes; - int updateVer = 0; + uint64_t updateVer = 0; - success = ParseUpdateManifest(text.c_str(), &updatesAvailable, notes, - updateVer); - if (!success) + if (!ParseUpdateManifest(text.c_str(), &updatesAvailable, notes, + updateVer, branch)) throw string("Failed to parse manifest"); if (!updatesAvailable && !repairMode) { @@ -653,8 +798,8 @@ /* ----------------------------------- * * skip this version if set to skip */ - int skipUpdateVer = config_get_int(GetGlobalConfig(), "General", - "SkipUpdateVersion"); + uint64_t skipUpdateVer = config_get_uint(GetGlobalConfig(), "General", + "SkipUpdateVersion"); if (!manualUpdate && updateVer == skipUpdateVer && !repairMode) return; @@ -682,8 +827,8 @@ return; } else if (queryResult == OBSUpdate::Skip) { - config_set_int(GetGlobalConfig(), "General", - "SkipUpdateVersion", updateVer); + config_set_uint(GetGlobalConfig(), "General", + "SkipUpdateVersion", updateVer); return; } } @@ -713,16 +858,19 @@ execInfo.cbSize = sizeof(execInfo); execInfo.lpFile = wUpdateFilePath; -#ifndef UPDATE_CHANNEL -#define UPDATE_ARG_SUFFIX L"" -#else -#define UPDATE_ARG_SUFFIX UPDATE_CHANNEL -#endif + + string parameters = ""; if (App()->IsPortableMode()) - execInfo.lpParameters = UPDATE_ARG_SUFFIX L" Portable"; - else - execInfo.lpParameters = UPDATE_ARG_SUFFIX; + parameters += "--portable"; + if (branch != WIN_DEFAULT_BRANCH) + parameters += "--branch=" + branch; + + BPtr<wchar_t> lpParameters; + size = os_utf8_to_wcs_ptr(parameters.c_str(), 0, &lpParameters); + if (!size && !parameters.empty()) + throw string("Could not convert parameters to wide"); + execInfo.lpParameters = lpParameters; execInfo.lpDirectory = cwd; execInfo.nShow = SW_SHOWNORMAL; @@ -737,8 +885,6 @@ * in case of issues with the new version */ config_set_int(GetGlobalConfig(), "General", "LastUpdateCheck", 0); config_set_int(GetGlobalConfig(), "General", "SkipUpdateVersion", 0); - config_set_string(GetGlobalConfig(), "General", "InstallGUID", - guid.c_str()); QMetaObject::invokeMethod(App()->GetMainWindow(), "close"); @@ -750,18 +896,8 @@ void WhatsNewInfoThread::run() try { - long responseCode; - vector<string> extraHeaders; string text; - string error; - string signature; CryptProvider localProvider; - BYTE whatsnewHashBLAKE2_HASH_LENGTH; - bool success; - - BPtr<char> whatsnewPath = - GetConfigPathPtr("obs-studio\\updates\\whatsnew.json"); - /* ----------------------------------- * * create signature provider */ @@ -772,71 +908,11 @@ provider = localProvider; - /* ----------------------------------- * - * avoid downloading json again */ - - if (CalculateFileHash(whatsnewPath, whatsnewHash)) { - char hashStringBLAKE2_HASH_STR_LENGTH; - HashToString(whatsnewHash, hashString); - - string header = "If-None-Match: "; - header += hashString; - extraHeaders.push_back(move(header)); + if (FetchAndVerifyFile("whatsnew", "obs-studio\\updates\\whatsnew.json", + WIN_WHATSNEW_URL, text)) { + emit Result(QString::fromStdString(text)); } - /* ----------------------------------- * - * get current install GUID */ - - string guid = GetProgramGUID(); - - if (!guid.empty()) { - string header = "X-OBS2-GUID: "; - header += guid; - extraHeaders.push_back(move(header)); - } - - /* ----------------------------------- * - * get json from server */ - - success = GetRemoteFile(WIN_WHATSNEW_URL, text, error, &responseCode, - nullptr, "", nullptr, extraHeaders, &signature); - - if (!success || (responseCode != 200 && responseCode != 304)) { - if (responseCode == 404) - return; - - throw strprintf("Failed to fetch whatsnew file: %s", - error.c_str()); - } - - /* ----------------------------------- * - * verify file signature */ - - if (responseCode == 200) { - success = CheckDataSignature(text, "whatsnew", signature.data(), - signature.size()); - if (!success) - throw string("Invalid whatsnew signature"); - } - - /* ----------------------------------- * - * write or load json */ - - if (responseCode == 200) { - if (!QuickWriteFile(whatsnewPath, text.data(), text.size())) - throw strprintf("Could not write file '%s'", - whatsnewPath.Get()); - } else { - if (!QuickReadFile(whatsnewPath, text)) - throw strprintf("Could not read file '%s'", - whatsnewPath.Get()); - } - - /* ----------------------------------- * - * success */ - - emit Result(QString::fromUtf8(text.c_str())); - } catch (string &text) { blog(LOG_WARNING, "%s: %s", __FUNCTION__, text.c_str()); }
View file
obs-studio-28.1.2.tar.xz/UI/window-basic-auto-config-test.cpp -> obs-studio-29.0.0.tar.xz/UI/window-basic-auto-config-test.cpp
Changed
@@ -894,6 +894,8 @@ wiz->streamingEncoder = AutoConfig::Encoder::NVENC; else if (wiz->qsvAvailable) wiz->streamingEncoder = AutoConfig::Encoder::QSV; + else if (wiz->appleAvailable) + wiz->streamingEncoder = AutoConfig::Encoder::Apple; else wiz->streamingEncoder = AutoConfig::Encoder::AMD; } else { @@ -927,6 +929,8 @@ wiz->recordingEncoder = AutoConfig::Encoder::NVENC; else if (wiz->qsvAvailable) wiz->recordingEncoder = AutoConfig::Encoder::QSV; + else if (wiz->appleAvailable) + wiz->recordingEncoder = AutoConfig::Encoder::Apple; else wiz->recordingEncoder = AutoConfig::Encoder::AMD; } else { @@ -948,6 +952,7 @@ #define ENCODER_NVENC ENCODER_TEXT("Hardware.NVENC.H264") #define ENCODER_QSV ENCODER_TEXT("Hardware.QSV.H264") #define ENCODER_AMD ENCODER_TEXT("Hardware.AMD.H264") +#define ENCODER_APPLE ENCODER_TEXT("Hardware.Apple.H264") #define QUALITY_SAME "Basic.Settings.Output.Simple.RecordingQuality.Stream" #define QUALITY_HIGH "Basic.Settings.Output.Simple.RecordingQuality.Small" @@ -990,6 +995,8 @@ return QTStr(ENCODER_QSV); case AutoConfig::Encoder::AMD: return QTStr(ENCODER_AMD); + case AutoConfig::Encoder::Apple: + return QTStr(ENCODER_APPLE); case AutoConfig::Encoder::Stream: return QTStr(QUALITY_SAME); }
View file
obs-studio-28.1.2.tar.xz/UI/window-basic-auto-config.cpp -> obs-studio-29.0.0.tar.xz/UI/window-basic-auto-config.cpp
Changed
@@ -969,7 +969,7 @@ /* Newer generations of NVENC have a high enough quality to * bitrate ratio that if NVENC is available, it makes sense to * just always prefer hardware encoding by default */ - bool preferHardware = nvencAvailable || + bool preferHardware = nvencAvailable || appleAvailable || os_get_physical_cores() <= 4; streamPage->ui->preferHardware->setChecked(preferHardware); } @@ -1000,6 +1000,18 @@ hardwareEncodingAvailable = qsvAvailable = true; else if (strcmp(id, "h264_texture_amf") == 0) hardwareEncodingAvailable = vceAvailable = true; +#ifdef __APPLE__ + else if (strcmp(id, + "com.apple.videotoolbox.videoencoder.ave.avc") == + 0 +#ifndef __aarch64__ + && os_get_emulation_status() == true +#endif + ) + if (__builtin_available(macOS 13.0, *)) + hardwareEncodingAvailable = appleAvailable = + true; +#endif } } @@ -1047,6 +1059,8 @@ return SIMPLE_ENCODER_QSV; case Encoder::AMD: return SIMPLE_ENCODER_AMD; + case Encoder::Apple: + return SIMPLE_ENCODER_APPLE_H264; default: return SIMPLE_ENCODER_X264; }
View file
obs-studio-28.1.2.tar.xz/UI/window-basic-auto-config.hpp -> obs-studio-29.0.0.tar.xz/UI/window-basic-auto-config.hpp
Changed
@@ -47,6 +47,7 @@ NVENC, QSV, AMD, + Apple, Stream, }; @@ -89,6 +90,7 @@ bool nvencAvailable = false; bool qsvAvailable = false; bool vceAvailable = false; + bool appleAvailable = false; int startingBitrate = 2500; bool customServer = false;
View file
obs-studio-28.1.2.tar.xz/UI/window-basic-main-outputs.cpp -> obs-studio-29.0.0.tar.xz/UI/window-basic-main-outputs.cpp
Changed
@@ -288,11 +288,14 @@ int CalcCRF(int crf); void UpdateRecordingSettings_x264_crf(int crf); - void UpdateRecordingSettings_qsv11(int crf); + void UpdateRecordingSettings_qsv11(int crf, bool av1); void UpdateRecordingSettings_nvenc(int cqp); void UpdateRecordingSettings_nvenc_hevc_av1(int cqp); void UpdateRecordingSettings_amd_cqp(int cqp); void UpdateRecordingSettings_apple(int quality); +#ifdef ENABLE_HEVC + void UpdateRecordingSettings_apple_hevc(int quality); +#endif void UpdateRecordingSettings(); void UpdateRecordingAudioSettings(); virtual void Update() override; @@ -367,13 +370,17 @@ } else if (strcmp(encoder, SIMPLE_ENCODER_X264_LOWCPU) == 0) { return "obs_x264"; } else if (strcmp(encoder, SIMPLE_ENCODER_QSV) == 0) { - return "obs_qsv11"; + return "obs_qsv11_v2"; + } else if (strcmp(encoder, SIMPLE_ENCODER_QSV_AV1) == 0) { + return "obs_qsv11_av1"; } else if (strcmp(encoder, SIMPLE_ENCODER_AMD) == 0) { return "h264_texture_amf"; #ifdef ENABLE_HEVC } else if (strcmp(encoder, SIMPLE_ENCODER_AMD_HEVC) == 0) { return "h265_texture_amf"; #endif + } else if (strcmp(encoder, SIMPLE_ENCODER_AMD_AV1) == 0) { + return "av1_texture_amf"; } else if (strcmp(encoder, SIMPLE_ENCODER_NVENC) == 0) { return EncoderAvailable("jim_nvenc") ? "jim_nvenc" : "ffmpeg_nvenc"; @@ -386,6 +393,10 @@ return "jim_av1_nvenc"; } else if (strcmp(encoder, SIMPLE_ENCODER_APPLE_H264) == 0) { return "com.apple.videotoolbox.videoencoder.ave.avc"; +#ifdef ENABLE_HEVC + } else if (strcmp(encoder, SIMPLE_ENCODER_APPLE_HEVC) == 0) { + return "com.apple.videotoolbox.videoencoder.ave.hevc"; +#endif } return "obs_x264"; @@ -526,6 +537,9 @@ if (strcmp(encoder, SIMPLE_ENCODER_QSV) == 0) { presetType = "QSVPreset"; + } else if (strcmp(encoder, SIMPLE_ENCODER_QSV_AV1) == 0) { + presetType = "QSVPreset"; + } else if (strcmp(encoder, SIMPLE_ENCODER_AMD) == 0) { presetType = "AMDPreset"; @@ -542,6 +556,9 @@ presetType = "NVENCPreset2"; #endif + } else if (strcmp(encoder, SIMPLE_ENCODER_AMD_AV1) == 0) { + presetType = "AMDAV1Preset"; + } else if (strcmp(encoder, SIMPLE_ENCODER_NVENC_AV1) == 0) { presetType = "NVENCPreset2"; @@ -653,21 +670,19 @@ return icq_found; } -void SimpleOutput::UpdateRecordingSettings_qsv11(int crf) +void SimpleOutput::UpdateRecordingSettings_qsv11(int crf, bool av1) { bool icq = icq_available(videoRecording); OBSDataAutoRelease settings = obs_data_create(); obs_data_set_string(settings, "profile", "high"); - if (icq) { + if (icq && !av1) { obs_data_set_string(settings, "rate_control", "ICQ"); obs_data_set_int(settings, "icq_quality", crf); } else { obs_data_set_string(settings, "rate_control", "CQP"); - obs_data_set_int(settings, "qpi", crf); - obs_data_set_int(settings, "qpp", crf); - obs_data_set_int(settings, "qpb", crf); + obs_data_set_int(settings, "cqp", crf); } obs_encoder_update(videoRecording, settings); @@ -703,6 +718,18 @@ obs_encoder_update(videoRecording, settings); } +#ifdef ENABLE_HEVC +void SimpleOutput::UpdateRecordingSettings_apple_hevc(int quality) +{ + OBSDataAutoRelease settings = obs_data_create(); + obs_data_set_string(settings, "rate_control", "CRF"); + obs_data_set_string(settings, "profile", "main"); + obs_data_set_int(settings, "quality", quality); + + obs_encoder_update(videoRecording, settings); +} +#endif + void SimpleOutput::UpdateRecordingSettings_amd_cqp(int cqp) { OBSDataAutoRelease settings = obs_data_create(); @@ -722,7 +749,10 @@ UpdateRecordingSettings_x264_crf(crf); } else if (videoEncoder == SIMPLE_ENCODER_QSV) { - UpdateRecordingSettings_qsv11(crf); + UpdateRecordingSettings_qsv11(crf, false); + + } else if (videoEncoder == SIMPLE_ENCODER_QSV_AV1) { + UpdateRecordingSettings_qsv11(crf, true); } else if (videoEncoder == SIMPLE_ENCODER_AMD) { UpdateRecordingSettings_amd_cqp(crf); @@ -745,6 +775,10 @@ } else if (videoEncoder == SIMPLE_ENCODER_APPLE_H264) { /* These are magic numbers. 0 - 100, more is better. */ UpdateRecordingSettings_apple(ultra_hq ? 70 : 50); +#ifdef ENABLE_HEVC + } else if (videoEncoder == SIMPLE_ENCODER_APPLE_HEVC) { + UpdateRecordingSettings_apple_hevc(ultra_hq ? 70 : 50); +#endif } UpdateRecordingAudioSettings(); } @@ -1323,7 +1357,7 @@ for (int i = 0; i < MAX_AUDIO_MIXES; i++) { char name9; - sprintf(name, "adv_aac%d", i); + snprintf(name, sizeof(name), "adv_aac%d", i); if (!CreateAACEncoder(aacTracki, aacEncoderIDi, GetAudioBitrate(i), name, i))
View file
obs-studio-28.1.2.tar.xz/UI/window-basic-main-profiles.cpp -> obs-studio-29.0.0.tar.xz/UI/window-basic-main-profiles.cpp
Changed
@@ -373,13 +373,15 @@ char profilePath512; char basePath512; - int ret = GetConfigPath(basePath, 512, "obs-studio/basic/profiles"); + int ret = GetConfigPath(basePath, sizeof(basePath), + "obs-studio/basic/profiles"); if (ret <= 0) { blog(LOG_WARNING, "Failed to get profiles config path"); return; } - ret = snprintf(profilePath, 512, "%s/%s/*", basePath, profileDir); + ret = snprintf(profilePath, sizeof(profilePath), "%s/%s/*", basePath, + profileDir); if (ret <= 0) { blog(LOG_WARNING, "Failed to get path for profile dir '%s'", profileDir); @@ -404,7 +406,8 @@ os_globfree(glob); - ret = snprintf(profilePath, 512, "%s/%s", basePath, profileDir); + ret = snprintf(profilePath, sizeof(profilePath), "%s/%s", basePath, + profileDir); if (ret <= 0) { blog(LOG_WARNING, "Failed to get path for profile dir '%s'", profileDir); @@ -819,12 +822,15 @@ const char *curRecEncoder = config_get_string(basicConfig, "SimpleOutput", "RecEncoder"); bool qsv_supported = false; + bool qsv_av1_supported = false; bool amd_supported = false; bool nve_supported = false; #ifdef ENABLE_HEVC bool amd_hevc_supported = false; bool nve_hevc_supported = false; + bool apple_hevc_supported = false; #endif + bool amd_av1_supported = false; bool apple_supported = false; bool changed = false; size_t idx = 0; @@ -835,6 +841,8 @@ amd_supported = true; else if (strcmp(id, "obs_qsv11") == 0) qsv_supported = true; + else if (strcmp(id, "obs_qsv11_av1") == 0) + qsv_av1_supported = true; else if (strcmp(id, "ffmpeg_nvenc") == 0) nve_supported = true; #ifdef ENABLE_HEVC @@ -843,10 +851,18 @@ else if (strcmp(id, "ffmpeg_hevc_nvenc") == 0) nve_hevc_supported = true; #endif + else if (strcmp(id, "av1_texture_amf") == 0) + amd_av1_supported = true; else if (strcmp(id, "com.apple.videotoolbox.videoencoder.ave.avc") == 0) apple_supported = true; +#ifdef ENABLE_HEVC + else if (strcmp(id, + "com.apple.videotoolbox.videoencoder.ave.hevc") == + 0) + apple_hevc_supported = true; +#endif } auto CheckEncoder = &(const char *&name) { @@ -856,6 +872,12 @@ name = SIMPLE_ENCODER_X264; return false; } + } else if (strcmp(name, SIMPLE_ENCODER_QSV_AV1) == 0) { + if (!qsv_av1_supported) { + changed = true; + name = SIMPLE_ENCODER_X264; + return false; + } } else if (strcmp(name, SIMPLE_ENCODER_NVENC) == 0) { if (!nve_supported) { changed = true; @@ -888,12 +910,26 @@ name = SIMPLE_ENCODER_X264; return false; } + } else if (strcmp(name, SIMPLE_ENCODER_AMD_AV1) == 0) { + if (!amd_av1_supported) { + changed = true; + name = SIMPLE_ENCODER_X264; + return false; + } } else if (strcmp(name, SIMPLE_ENCODER_APPLE_H264) == 0) { if (!apple_supported) { changed = true; name = SIMPLE_ENCODER_X264; return false; } +#ifdef ENABLE_HEVC + } else if (strcmp(name, SIMPLE_ENCODER_APPLE_HEVC) == 0) { + if (!apple_hevc_supported) { + changed = true; + name = SIMPLE_ENCODER_X264; + return false; + } +#endif } return true;
View file
obs-studio-28.1.2.tar.xz/UI/window-basic-main-screenshot.cpp -> obs-studio-29.0.0.tar.xz/UI/window-basic-main-screenshot.cpp
Changed
@@ -53,6 +53,12 @@ main->ShowStatusBarMessage( QTStr("Basic.StatusBar.ScreenshotSavedTo") .arg(QT_UTF8(path.c_str()))); + + main->lastScreenshot = path; + + if (main->api) + main->api->on_event( + OBS_FRONTEND_EVENT_SCREENSHOT_TAKEN); } } }
View file
obs-studio-28.1.2.tar.xz/UI/window-basic-main-transitions.cpp -> obs-studio-29.0.0.tar.xz/UI/window-basic-main-transitions.cpp
Changed
@@ -1053,7 +1053,7 @@ return menu; } -void OBSBasic::on_actionShowTransitionProperties_triggered() +void OBSBasic::ShowTransitionProperties() { OBSSceneItem item = GetCurrentSceneItem(); OBSSource source = obs_sceneitem_get_transition(item, true); @@ -1062,7 +1062,7 @@ CreatePropertiesWindow(source); } -void OBSBasic::on_actionHideTransitionProperties_triggered() +void OBSBasic::HideTransitionProperties() { OBSSceneItem item = GetCurrentSceneItem(); OBSSource source = obs_sceneitem_get_transition(item, false); @@ -1247,10 +1247,9 @@ menu->addAction(durationAction); if (curId && obs_is_source_configurable(curId)) { menu->addSeparator(); - menu->addAction( - QTStr("Properties"), this, - visible ? SLOT(on_actionShowTransitionProperties_triggered()) - : SLOT(on_actionHideTransitionProperties_triggered())); + menu->addAction(QTStr("Properties"), this, + visible ? SLOT(ShowTransitionProperties()) + : SLOT(HideTransitionProperties())); } auto copyTransition = this(QAction *, bool visible) {
View file
obs-studio-28.1.2.tar.xz/UI/window-basic-main.cpp -> obs-studio-29.0.0.tar.xz/UI/window-basic-main.cpp
Changed
@@ -272,14 +272,14 @@ setAcceptDrops(true); setContextMenuPolicy(Qt::CustomContextMenu); - connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, - SLOT(on_customContextMenuRequested(const QPoint &))); api = InitializeAPIInterface(this); ui->setupUi(this); ui->previewDisabledWidget->setVisible(false); - ui->contextContainer->setStyle(new OBSContextBarProxyStyle); + QStyle *contextBarStyle = new OBSContextBarProxyStyle(); + contextBarStyle->setParent(ui->contextContainer); + ui->contextContainer->setStyle(contextBarStyle); ui->broadcastButton->setVisible(false); startingDockLayout = saveState(); @@ -1399,7 +1399,7 @@ config_set_default_string(basicConfig, "SimpleOutput", "Preset", "veryfast"); config_set_default_string(basicConfig, "SimpleOutput", "NVENCPreset2", - "p6"); + "p5"); config_set_default_string(basicConfig, "SimpleOutput", "RecQuality", "Stream"); config_set_default_bool(basicConfig, "SimpleOutput", "RecRB", false); @@ -1882,7 +1882,6 @@ disableSaving++; } - TimedCheckForUpdates(); loaded = true; previewEnabled = config_get_bool(App()->GlobalConfig(), "BasicWindow", @@ -1893,15 +1892,6 @@ Qt::QueuedConnection, Q_ARG(bool, previewEnabled)); -#ifdef _WIN32 - uint32_t winVer = GetWindowsVersion(); - if (winVer > 0 && winVer < 0x602) { - bool disableAero = - config_get_bool(basicConfig, "Video", "DisableAero"); - SetAeroEnabled(!disableAero); - } -#endif - RefreshSceneCollections(); RefreshProfiles(); disableSaving--; @@ -2036,6 +2026,19 @@ QMetaObject::invokeMethod(this, "on_autoConfigure_triggered", Qt::QueuedConnection); +#if defined(_WIN32) && (OBS_RELEASE_CANDIDATE > 0 || OBS_BETA > 0) + /* Automatically set branch to "beta" the first time a pre-release build is run. */ + if (!config_get_bool(App()->GlobalConfig(), "General", + "AutoBetaOptIn")) { + config_set_string(App()->GlobalConfig(), "General", + "UpdateBranch", "beta"); + config_set_bool(App()->GlobalConfig(), "General", + "AutoBetaOptIn", true); + config_save_safe(App()->GlobalConfig(), "tmp", nullptr); + } +#endif + TimedCheckForUpdates(); + ToggleMixerLayout(config_get_bool(App()->GlobalConfig(), "BasicWindow", "VerticalVolControl")); @@ -2717,17 +2720,6 @@ ui->lockDocks->isChecked()); config_save_safe(App()->GlobalConfig(), "tmp", nullptr); -#ifdef _WIN32 - uint32_t winVer = GetWindowsVersion(); - if (winVer > 0 && winVer < 0x602) { - bool disableAero = - config_get_bool(basicConfig, "Video", "DisableAero"); - if (disableAero) { - SetAeroEnabled(true); - } - } -#endif - #ifdef BROWSER_AVAILABLE DestroyPanelCookieManager(); delete cef; @@ -3097,13 +3089,26 @@ Qt::QueuedConnection, Q_ARG(bool, force)); } +void OBSBasic::SourceToolBarActionsSetEnabled(bool enable) +{ + ui->actionRemoveSource->setEnabled(enable); + ui->actionSourceProperties->setEnabled(enable); + ui->actionSourceUp->setEnabled(enable); + ui->actionSourceDown->setEnabled(enable); + + RefreshToolBarStyling(ui->sourcesToolbar); +} + void OBSBasic::UpdateContextBar(bool force) { + OBSSceneItem item = GetCurrentSceneItem(); + bool enable = item != nullptr; + + SourceToolBarActionsSetEnabled(enable); + if (!ui->contextContainer->isVisible() && !force) return; - OBSSceneItem item = GetCurrentSceneItem(); - if (item) { obs_source_t *source = obs_sceneitem_get_source(item); @@ -5056,13 +5061,13 @@ QRect screenGeometry = screen->geometry(); qreal ratio = screen->devicePixelRatio(); QString name = ""; -#ifdef _WIN32 +#if defined(_WIN32) && QT_VERSION < QT_VERSION_CHECK(6, 4, 0) QTextStream fullname(&name); fullname << GetMonitorName(screen->name()); fullname << " ("; fullname << (i + 1); fullname << ")"; -#elif defined(__APPLE__) +#elif defined(__APPLE__) || defined(_WIN32) name = screen->name(); #else name = screen->model().simplified(); @@ -7166,7 +7171,16 @@ QString output = input; output.resize(output.size() - suffix.size()); - output += "mp4"; + + const obs_encoder_t *videoEncoder = + obs_output_get_video_encoder(outputHandler->fileOutput); + const char *codecName = obs_encoder_get_codec(videoEncoder); + + if (strcmp(codecName, "prores") == 0) { + output += "mov"; + } else { + output += "mp4"; + } OBSRemux *remux = new OBSRemux(QT_TO_UTF8(path), this, true); if (!no_show) @@ -7478,15 +7492,17 @@ proc_handler_t *ph = obs_output_get_proc_handler(outputHandler->replayBuffer); proc_handler_call(ph, "get_last_replay", &cd); - QString path = QT_UTF8(calldata_string(&cd, "path")); - QString msg = QTStr("Basic.StatusBar.ReplayBufferSavedTo").arg(path); + std::string path = calldata_string(&cd, "path"); + QString msg = QTStr("Basic.StatusBar.ReplayBufferSavedTo") + .arg(QT_UTF8(path.c_str())); ShowStatusBarMessage(msg); + lastReplay = path; calldata_free(&cd); if (api) api->on_event(OBS_FRONTEND_EVENT_REPLAY_BUFFER_SAVED); - AutoRemux(path); + AutoRemux(QT_UTF8(path.c_str())); } void OBSBasic::ReplayBufferStop(int code) @@ -10151,7 +10167,7 @@ foreach(OBSBasicStats * s, list) s->Reset(); } -void OBSBasic::on_customContextMenuRequested(const QPoint &pos) +void OBSBasic::on_OBSBasic_customContextMenuRequested(const QPoint &pos) { QWidget *widget = childAt(pos); const char *className = nullptr; @@ -10206,6 +10222,14 @@ OpenFilters(); } +void OBSBasic::on_actionSceneFilters_triggered() +{ + OBSSource sceneSource = GetCurrentSceneSource(); + + if (sceneSource) + OpenFilters(sceneSource); +} + void OBSBasic::on_sourceInteractButton_clicked() { on_actionInteract_triggered(); @@ -10318,4 +10342,7 @@ ActivateAudioSource(source); UpdateContextBar(true); + + if (api) + api->on_event(OBS_FRONTEND_EVENT_THEME_CHANGED); }
View file
obs-studio-28.1.2.tar.xz/UI/window-basic-main.hpp -> obs-studio-29.0.0.tar.xz/UI/window-basic-main.hpp
Changed
@@ -65,12 +65,15 @@ #define SIMPLE_ENCODER_X264 "x264" #define SIMPLE_ENCODER_X264_LOWCPU "x264_lowcpu" #define SIMPLE_ENCODER_QSV "qsv" +#define SIMPLE_ENCODER_QSV_AV1 "qsv_av1" #define SIMPLE_ENCODER_NVENC "nvenc" #define SIMPLE_ENCODER_NVENC_AV1 "nvenc_av1" #define SIMPLE_ENCODER_NVENC_HEVC "nvenc_hevc" #define SIMPLE_ENCODER_AMD "amd" #define SIMPLE_ENCODER_AMD_HEVC "amd_hevc" +#define SIMPLE_ENCODER_AMD_AV1 "amd_av1" #define SIMPLE_ENCODER_APPLE_H264 "apple_h264" +#define SIMPLE_ENCODER_APPLE_HEVC "apple_hevc" #define PREVIEW_EDGE_SIZE 10 @@ -189,6 +192,7 @@ friend class OBSPermissions; friend struct BasicOutputHandler; friend struct OBSStudioAPI; + friend class ScreenshotObj; enum class MoveDir { Up, Down, Left, Right }; @@ -634,6 +638,10 @@ bool drawSpacingHelpers = true; float GetDevicePixelRatio(); + void SourceToolBarActionsSetEnabled(bool enable); + + std::string lastScreenshot; + std::string lastReplay; public slots: void DeferSaveBegin(); @@ -1026,8 +1034,9 @@ void on_actionCenterToScreen_triggered(); void on_actionVerticalCenter_triggered(); void on_actionHorizontalCenter_triggered(); + void on_actionSceneFilters_triggered(); - void on_customContextMenuRequested(const QPoint &pos); + void on_OBSBasic_customContextMenuRequested(const QPoint &pos); void on_scenes_currentItemChanged(QListWidgetItem *current, QListWidgetItem *prev); @@ -1107,8 +1116,8 @@ void on_transitionDuration_valueChanged(int value); void on_tbar_position_valueChanged(int value); - void on_actionShowTransitionProperties_triggered(); - void on_actionHideTransitionProperties_triggered(); + void ShowTransitionProperties(); + void HideTransitionProperties(); void on_modeSwitch_clicked();
View file
obs-studio-28.1.2.tar.xz/UI/window-basic-settings-stream.cpp -> obs-studio-29.0.0.tar.xz/UI/window-basic-settings-stream.cpp
Changed
@@ -132,6 +132,29 @@ ui->authUsername->setText(QT_UTF8(username)); ui->authPw->setText(QT_UTF8(password)); ui->useAuth->setChecked(use_auth); + + /* add tooltips for stream key, user, password fields */ + QString file = !App()->IsThemeDark() + ? ":/res/images/help.svg" + : ":/res/images/help_light.svg"; + QString lStr = "<html>%1 <img src='%2' style=' \ + vertical-align: bottom; \ + ' /></html>"; + + ui->streamKeyLabel->setText( + lStr.arg(ui->streamKeyLabel->text(), file)); + ui->streamKeyLabel->setToolTip( + QTStr("Basic.AutoConfig.StreamPage.StreamKey.ToolTip")); + + ui->authUsernameLabel->setText( + lStr.arg(ui->authUsernameLabel->text(), file)); + ui->authUsernameLabel->setToolTip( + QTStr("Basic.Settings.Stream.Custom.Username.ToolTip")); + + ui->authPwLabel->setText( + lStr.arg(ui->authPwLabel->text(), file)); + ui->authPwLabel->setToolTip( + QTStr("Basic.Settings.Stream.Custom.Password.ToolTip")); } else { int idx = ui->service->findText(service); if (idx == -1) { @@ -305,7 +328,7 @@ if (serviceName == "Dacast") { ui->streamKeyLabel->setText( QTStr("Basic.AutoConfig.StreamPage.EncoderKey")); - } else { + } else if (!IsCustomService()) { ui->streamKeyLabel->setText( QTStr("Basic.AutoConfig.StreamPage.StreamKey")); } @@ -1244,6 +1267,8 @@ return "jim_nvenc"; if (enc == "h265_texture_amf") return "h264_texture_amf"; + if (enc == "com.apple.videotoolbox.videoencoder.ave.hevc") + return "com.apple.videotoolbox.videoencoder.ave.avc"; return "obs_x264"; } @@ -1255,6 +1280,8 @@ return SIMPLE_ENCODER_NVENC; if (enc == SIMPLE_ENCODER_AMD_HEVC) return SIMPLE_ENCODER_AMD; + if (enc == SIMPLE_ENCODER_APPLE_HEVC) + return SIMPLE_ENCODER_APPLE_H264; return SIMPLE_ENCODER_X264; } @@ -1315,7 +1342,7 @@ void OBSBasicSettings::ResetEncoders(bool streamOnly) { - QString lastAdvEnc = ui->advOutRecEncoder->currentData().toString(); + QString lastAdvEnc = ui->advOutEncoder->currentData().toString(); QString lastEnc = ui->simpleOutStrEncoder->currentData().toString(); OBSService service = SpawnTempService(); const char **codecs = obs_service_get_supported_video_codecs(service); @@ -1384,6 +1411,10 @@ ui->simpleOutStrEncoder->addItem( ENCODER_STR("Hardware.QSV.H264"), QString(SIMPLE_ENCODER_QSV)); + if (service_supports_encoder(codecs, "obs_qsv11_av1")) + ui->simpleOutStrEncoder->addItem( + ENCODER_STR("Hardware.QSV.AV1"), + QString(SIMPLE_ENCODER_QSV_AV1)); if (service_supports_encoder(codecs, "ffmpeg_nvenc")) ui->simpleOutStrEncoder->addItem( ENCODER_STR("Hardware.NVENC.H264"), @@ -1420,6 +1451,20 @@ QString(SIMPLE_ENCODER_APPLE_H264)); } } +#ifdef ENABLE_HEVC + if (service_supports_encoder( + codecs, "com.apple.videotoolbox.videoencoder.ave.hevc") +#ifndef __aarch64__ + && os_get_emulation_status() == true +#endif + ) { + if (__builtin_available(macOS 13.0, *)) { + ui->simpleOutStrEncoder->addItem( + ENCODER_STR("Hardware.Apple.HEVC"), + QString(SIMPLE_ENCODER_APPLE_HEVC)); + } + } +#endif #endif #undef ENCODER_STR
View file
obs-studio-28.1.2.tar.xz/UI/window-basic-settings.cpp -> obs-studio-29.0.0.tar.xz/UI/window-basic-settings.cpp
Changed
@@ -259,13 +259,6 @@ id); } -#ifdef _WIN32 -void OBSBasicSettings::ToggleDisableAero(bool checked) -{ - SetAeroEnabled(!checked); -} -#endif - static void PopulateAACBitrates(initializer_list<QComboBox *> boxes) { auto &bitrateMap = GetAACEncoderBitrateMap(); @@ -380,6 +373,7 @@ /* clang-format off */ HookWidget(ui->language, COMBO_CHANGED, GENERAL_CHANGED); HookWidget(ui->theme, COMBO_CHANGED, GENERAL_CHANGED); + HookWidget(ui->updateChannelBox, COMBO_CHANGED, GENERAL_CHANGED); HookWidget(ui->enableAutoUpdates, CHECK_CHANGED, GENERAL_CHANGED); HookWidget(ui->openStatsOnStartup, CHECK_CHANGED, GENERAL_CHANGED); HookWidget(ui->hideOBSFromCapture, CHECK_CHANGED, GENERAL_CHANGED); @@ -587,6 +581,19 @@ #if !defined(_WIN32) && !defined(__APPLE__) delete ui->enableAutoUpdates; ui->enableAutoUpdates = nullptr; + delete ui->updateChannelBox; + ui->updateChannelBox = nullptr; + delete ui->updateSettingsGroupBox; + ui->updateSettingsGroupBox = nullptr; +#elif defined(__APPLE__) + delete ui->updateChannelBox; + ui->updateChannelBox = nullptr; + delete ui->updateChannelLabel; + ui->updateChannelLabel = nullptr; +#else + // Hide update section if disabled + if (App()->IsUpdaterDisabled()) + ui->updateSettingsGroupBox->hide(); #endif // Remove the Advanced Audio section if monitoring is not supported, as the monitoring device selection is the only item in the group box. @@ -598,20 +605,6 @@ } #ifdef _WIN32 - uint32_t winVer = GetWindowsVersion(); - if (winVer > 0 && winVer < 0x602) { - // Older than Windows 8 - toggleAero = new QCheckBox( - QTStr("Basic.Settings.Video.DisableAero"), this); - QFormLayout *videoLayout = reinterpret_cast<QFormLayout *>( - ui->videoPage->layout()); - videoLayout->addRow(nullptr, toggleAero); - - HookWidget(toggleAero, CHECK_CHANGED, VIDEO_CHANGED); - connect(toggleAero, &QAbstractButton::toggled, this, - &OBSBasicSettings::ToggleDisableAero); - } - if (!SetDisplayAffinitySupported()) { delete ui->hideOBSFromCapture; ui->hideOBSFromCapture = nullptr; @@ -823,8 +816,6 @@ SLOT(AdvReplayBufferChanged())); connect(ui->advRBSecMax, SIGNAL(valueChanged(int)), this, SLOT(AdvReplayBufferChanged())); - connect(ui->listWidget, SIGNAL(currentRowChanged(int)), this, - SLOT(SimpleRecordingEncoderChanged())); // Get Bind to IP Addresses obs_properties_t *ppts = obs_get_output_properties("rtmp_output"); @@ -910,10 +901,10 @@ SLOT(AdvOutRecCheckWarnings())); connect(ui->advOutRecEncoder, SIGNAL(currentIndexChanged(int)), this, SLOT(AdvOutRecCheckWarnings())); - AdvOutRecCheckWarnings(); SimpleRecordingQualityChanged(); AdvOutSplitFileChanged(); + AdvOutRecCheckWarnings(); UpdateAutomaticReplayBufferCheckboxes(); @@ -1020,7 +1011,7 @@ #define CF_I444_STR QTStr("Basic.Settings.Advanced.Video.ColorFormat.I444") #define CF_P010_STR QTStr("Basic.Settings.Advanced.Video.ColorFormat.P010") #define CF_I010_STR QTStr("Basic.Settings.Advanced.Video.ColorFormat.I010") -#define CF_RGB_STR QTStr("Basic.Settings.Advanced.Video.ColorFormat.RGB") +#define CF_BGRA_STR QTStr("Basic.Settings.Advanced.Video.ColorFormat.BGRA") void OBSBasicSettings::LoadColorFormats() { @@ -1029,7 +1020,7 @@ ui->colorFormat->addItem(CF_I444_STR, "I444"); ui->colorFormat->addItem(CF_P010_STR, "P010"); ui->colorFormat->addItem(CF_I010_STR, "I010"); - ui->colorFormat->addItem(CF_RGB_STR, "RGB"); + ui->colorFormat->addItem(CF_BGRA_STR, "RGB"); // Avoid config break } #define AV_FORMAT_DEFAULT_STR \ @@ -1215,6 +1206,73 @@ ui->theme->setCurrentIndex(idx); } +#ifdef _WIN32 +void TranslateBranchInfo(const QString &name, QString &displayName, + QString &description) +{ + QString translatedName = + QTStr("Basic.Settings.General.ChannelName." + name.toUtf8()); + QString translatedDesc = QTStr( + "Basic.Settings.General.ChannelDescription." + name.toUtf8()); + + if (!translatedName.startsWith("Basic.Settings.")) + displayName = translatedName; + if (!translatedDesc.startsWith("Basic.Settings.")) + description = translatedDesc; +} +#endif + +void OBSBasicSettings::LoadBranchesList() +{ +#ifdef _WIN32 + bool configBranchRemoved = true; + QString configBranch = + config_get_string(GetGlobalConfig(), "General", "UpdateBranch"); + + for (const UpdateBranch &branch : App()->GetBranches()) { + if (branch.name == configBranch) + configBranchRemoved = false; + if (!branch.is_visible && branch.name != configBranch) + continue; + + QString displayName = branch.display_name; + QString description = branch.description; + + TranslateBranchInfo(branch.name, displayName, description); + QString itemDesc = displayName + " - " + description; + + if (!branch.is_enabled) { + itemDesc.prepend(" "); + itemDesc.prepend(QTStr( + "Basic.Settings.General.UpdateChannelDisabled")); + } else if (branch.name == "stable") { + itemDesc.append(" "); + itemDesc.append(QTStr( + "Basic.Settings.General.UpdateChannelDefault")); + } + + ui->updateChannelBox->addItem(itemDesc, branch.name); + + // Disable item if branch is disabled + if (!branch.is_enabled) { + QStandardItemModel *model = + dynamic_cast<QStandardItemModel *>( + ui->updateChannelBox->model()); + QStandardItem *item = + model->item(ui->updateChannelBox->count() - 1); + item->setFlags(Qt::NoItemFlags); + } + } + + // Fall back to default if not yet set or user-selected branch has been removed + if (configBranch.isEmpty() || configBranchRemoved) + configBranch = "stable"; + + int idx = ui->updateChannelBox->findData(configBranch); + ui->updateChannelBox->setCurrentIndex(idx); +#endif +} + void OBSBasicSettings::LoadGeneralSettings() { loading = true; @@ -1226,6 +1284,10 @@ bool enableAutoUpdates = config_get_bool(GetGlobalConfig(), "General", "EnableAutoUpdates"); ui->enableAutoUpdates->setChecked(enableAutoUpdates); + +#ifdef _WIN32 + LoadBranchesList(); +#endif #endif bool openStatsOnStartup = config_get_bool(main->Config(), "General", "OpenStatsOnStartup"); @@ -1707,16 +1769,6 @@ LoadFPSData(); LoadDownscaleFilters(); -#ifdef _WIN32 - if (toggleAero) { - bool disableAero = - config_get_bool(main->Config(), "Video", "DisableAero"); - toggleAero->setChecked(disableAero); - - aeroWasDisabled = disableAero; - } -#endif - loading = false; } @@ -1762,6 +1814,8 @@ "NVENCPreset2"); const char *amdPreset = config_get_string(main->Config(), "SimpleOutput", "AMDPreset"); + const char *amdAV1Preset = config_get_string( + main->Config(), "SimpleOutput", "AMDAV1Preset"); const char *custom = config_get_string(main->Config(), "SimpleOutput", "x264Settings"); const char *recQual = @@ -1781,6 +1835,7 @@ curQSVPreset = qsvPreset; curNVENCPreset = nvPreset; curAMDPreset = amdPreset; + curAMDAV1Preset = amdAV1Preset; audioBitrate = FindClosestAvailableAACBitrate(audioBitrate); @@ -3066,6 +3121,16 @@ ui->enableAutoUpdates->isChecked()); #endif #ifdef _WIN32 + int branchIdx = ui->updateChannelBox->currentIndex(); + QString branchName = + ui->updateChannelBox->itemData(branchIdx).toString(); + + if (WidgetChanged(ui->updateChannelBox)) { + config_set_string(GetGlobalConfig(), "General", "UpdateBranch", + QT_TO_UTF8(branchName)); + forceUpdateCheck = true; + } + if (ui->hideOBSFromCapture && WidgetChanged(ui->hideOBSFromCapture)) { bool hide_window = ui->hideOBSFromCapture->isChecked(); config_set_bool(GetGlobalConfig(), "BasicWindow", @@ -3292,13 +3357,6 @@ SaveSpinBox(ui->fpsNumerator, "Video", "FPSNum"); SaveSpinBox(ui->fpsDenominator, "Video", "FPSDen"); SaveComboData(ui->downscaleFilter, "Video", "ScaleType"); - -#ifdef _WIN32 - if (toggleAero) { - SaveCheckBox(toggleAero, "Video", "DisableAero"); - aeroWasDisabled = toggleAero->isChecked(); - } -#endif } void OBSBasicSettings::SaveAdvancedSettings() @@ -3519,6 +3577,8 @@ if (encoder == SIMPLE_ENCODER_QSV) presetType = "QSVPreset"; + else if (encoder == SIMPLE_ENCODER_QSV_AV1) + presetType = "QSVPreset"; else if (encoder == SIMPLE_ENCODER_NVENC) presetType = "NVENCPreset2"; else if (encoder == SIMPLE_ENCODER_NVENC_AV1) @@ -3531,7 +3591,13 @@ #endif else if (encoder == SIMPLE_ENCODER_AMD) presetType = "AMDPreset"; - else if (encoder == SIMPLE_ENCODER_APPLE_H264) + else if (encoder == SIMPLE_ENCODER_AMD_AV1) + presetType = "AMDAV1Preset"; + else if (encoder == SIMPLE_ENCODER_APPLE_H264 +#ifdef ENABLE_HEVC + || encoder == SIMPLE_ENCODER_APPLE_HEVC +#endif + ) /* The Apple encoders don't have presets like the other encoders do. This only exists to make sure that the x264 preset doesn't get overwritten with empty data. */ @@ -3894,10 +3960,6 @@ App()->SetTheme(savedTheme); LoadSettings(true); -#ifdef _WIN32 - if (toggleAero) - SetAeroEnabled(!aeroWasDisabled); -#endif restart = false; } @@ -3949,10 +4011,6 @@ if (val == QDialogButtonBox::RejectRole) { if (savedTheme != App()->GetTheme()) App()->SetTheme(savedTheme); -#ifdef _WIN32 - if (toggleAero) - SetAeroEnabled(!aeroWasDisabled); -#endif } ClearChanged(); close(); @@ -4181,6 +4239,11 @@ forceAuthReload = false; } + if (forceUpdateCheck) { + main->CheckForUpdates(false); + forceUpdateCheck = false; + } + return canCloseSettings; } @@ -4634,17 +4697,51 @@ errorMsg = QTStr("OutputWarnings.NoTracksSelected"); } - if (ui->advOutRecFormat->currentText().compare("mp4") == 0 || - ui->advOutRecFormat->currentText().compare("mov") == 0) { - if (!warningMsg.isEmpty()) - warningMsg += "\n\n"; - warningMsg += QTStr("OutputWarnings.MP4Recording"); - ui->autoRemux->setText( - QTStr("Basic.Settings.Advanced.AutoRemux") + " " + - QTStr("Basic.Settings.Advanced.AutoRemux.MP4")); + QString recFormat = ui->advOutRecFormat->currentText(); + QString recEncoder = ui->advOutRecEncoder->currentText(); + + if (recEncoder.contains("ProRes")) { + if (recFormat.compare("mkv") == 0) { + ui->autoRemux->setText( + QTStr("Basic.Settings.Advanced.AutoRemux") + .arg("mov")); + } else if (recFormat.compare("mov") == 0) { + if (!warningMsg.isEmpty()) { + warningMsg += "\n\n"; + } + + warningMsg += QTStr("OutputWarnings.MP4Recording"); + ui->autoRemux->setText( + QTStr("Basic.Settings.Advanced.AutoRemux") + .arg("mov") + + " " + + QTStr("Basic.Settings.Advanced.AutoRemux.MP4")); + } else { + if (!errorMsg.isEmpty()) { + errorMsg += "\n\n"; + } + + errorMsg += QTStr("OutputWarnings.ProResRecording") + .arg(recFormat); + } } else { - ui->autoRemux->setText( - QTStr("Basic.Settings.Advanced.AutoRemux")); + if (recFormat.compare("mp4") == 0 || + recFormat.compare("mov") == 0) { + if (!warningMsg.isEmpty()) { + warningMsg += "\n\n"; + } + + warningMsg += QTStr("OutputWarnings.MP4Recording"); + ui->autoRemux->setText( + QTStr("Basic.Settings.Advanced.AutoRemux") + .arg("mp4") + + " " + + QTStr("Basic.Settings.Advanced.AutoRemux.MP4")); + } else { + ui->autoRemux->setText( + QTStr("Basic.Settings.Advanced.AutoRemux") + .arg("mp4")); + } } delete advOutRecWarning; @@ -4764,6 +4861,10 @@ ui->simpleOutRecEncoder->addItem( ENCODER_STR("Hardware.QSV.H264"), QString(SIMPLE_ENCODER_QSV)); + if (EncoderAvailable("obs_qsv11_av1")) + ui->simpleOutRecEncoder->addItem( + ENCODER_STR("Hardware.QSV.AV1"), + QString(SIMPLE_ENCODER_QSV_AV1)); if (EncoderAvailable("ffmpeg_nvenc")) ui->simpleOutRecEncoder->addItem( ENCODER_STR("Hardware.NVENC.H264"), @@ -4786,6 +4887,10 @@ ui->simpleOutRecEncoder->addItem( ENCODER_STR("Hardware.AMD.H264"), QString(SIMPLE_ENCODER_AMD)); + if (EncoderAvailable("av1_texture_amf")) + ui->simpleOutRecEncoder->addItem( + ENCODER_STR("Hardware.AMD.AV1"), + QString(SIMPLE_ENCODER_AMD_AV1)); if (EncoderAvailable("com.apple.videotoolbox.videoencoder.ave.avc") #ifndef __aarch64__ && os_get_emulation_status() == true @@ -4794,6 +4899,17 @@ ui->simpleOutRecEncoder->addItem( ENCODER_STR("Hardware.Apple.H264"), QString(SIMPLE_ENCODER_APPLE_H264)); +#ifdef ENABLE_HEVC + if (EncoderAvailable("com.apple.videotoolbox.videoencoder.ave.hevc") +#ifndef __aarch64__ + && os_get_emulation_status() == true +#endif + ) + ui->simpleOutRecEncoder->addItem( + ENCODER_STR("Hardware.Apple.HEVC"), + QString(SIMPLE_ENCODER_APPLE_HEVC)); +#endif + #undef ADD_QUALITY #undef ENCODER_STR } @@ -4844,7 +4960,8 @@ ui->simpleOutPreset->setVisible(true); ui->simpleOutPreset->clear(); - if (encoder == SIMPLE_ENCODER_QSV) { + if (encoder == SIMPLE_ENCODER_QSV || + encoder == SIMPLE_ENCODER_QSV_AV1) { ui->simpleOutPreset->addItem("speed", "speed"); ui->simpleOutPreset->addItem("balanced", "balanced"); ui->simpleOutPreset->addItem("quality", "quality"); @@ -4882,11 +4999,24 @@ defaultPreset = "balanced"; preset = curAMDPreset; - } else if (encoder == SIMPLE_ENCODER_APPLE_H264) { + } else if (encoder == SIMPLE_ENCODER_APPLE_H264 +#ifdef ENABLE_HEVC + || encoder == SIMPLE_ENCODER_APPLE_HEVC +#endif + ) { ui->simpleOutAdvanced->setChecked(false); ui->simpleOutAdvanced->setVisible(false); ui->simpleOutPreset->setVisible(false); ui->simpleOutPresetLabel->setVisible(false); + + } else if (encoder == SIMPLE_ENCODER_AMD_AV1) { + ui->simpleOutPreset->addItem("Speed", "speed"); + ui->simpleOutPreset->addItem("Balanced", "balanced"); + ui->simpleOutPreset->addItem("Quality", "quality"); + ui->simpleOutPreset->addItem("High Quality", "highQuality"); + + defaultPreset = "balanced"; + preset = curAMDAV1Preset; } else { #define PRESET_STR(val) \ @@ -4925,6 +5055,8 @@ } #define ESTIMATE_STR "Basic.Settings.Output.ReplayBuffer.Estimate" +#define ESTIMATE_TOO_LARGE_STR \ + "Basic.Settings.Output.ReplayBuffer.EstimateTooLarge" #define ESTIMATE_UNKNOWN_STR \ "Basic.Settings.Output.ReplayBuffer.EstimateUnknown" @@ -4962,17 +5094,33 @@ int abitrate = ui->simpleOutputABitrate->currentText().toInt(); int seconds = ui->simpleRBSecMax->value(); + // Set maximum to 75% of installed memory + uint64_t memTotal = os_get_sys_total_size(); + int64_t memMaxMB = memTotal ? memTotal * 3 / 4 / 1024 / 1024 : 8192; + int64_t memMB = int64_t(seconds) * int64_t(vbitrate + abitrate) * 1000 / 8 / 1024 / 1024; if (memMB < 1) memMB = 1; - if (streamQuality) - ui->simpleRBEstimate->setText( - QTStr(ESTIMATE_STR).arg(QString::number(int(memMB)))); - else + ui->simpleRBEstimate->setObjectName(""); + if (streamQuality) { + if (memMB <= memMaxMB) { + ui->simpleRBEstimate->setText( + QTStr(ESTIMATE_STR) + .arg(QString::number(int(memMB)))); + } else { + ui->simpleRBEstimate->setText( + QTStr(ESTIMATE_TOO_LARGE_STR) + .arg(QString::number(int(memMB)), + QString::number(int(memMaxMB)))); + ui->simpleRBEstimate->setObjectName("warningLabel"); + } + } else { ui->simpleRBEstimate->setText(QTStr(ESTIMATE_UNKNOWN_STR)); + } + ui->simpleRBEstimate->style()->polish(ui->simpleRBEstimate); ui->replayBufferGroupBox->setVisible(!lossless && replayBufferEnabled); ui->simpleReplayBuf->setVisible(!lossless); @@ -5038,6 +5186,10 @@ int seconds = ui->advRBSecMax->value(); + // Set maximum to 75% of installed memory + uint64_t memTotal = os_get_sys_total_size(); + int64_t memMaxMB = memTotal ? memTotal * 3 / 4 / 1024 / 1024 : 8192; + int64_t memMB = int64_t(seconds) * int64_t(vbitrate + abitrate) * 1000 / 8 / 1024 / 1024; if (memMB < 1) @@ -5049,16 +5201,31 @@ if (vbitrate == 0) varRateControl = false; - ui->advRBMegsMax->setVisible(!varRateControl); - ui->advRBMegsMaxLabel->setVisible(!varRateControl); - - if (varRateControl) - ui->advRBEstimate->setText( - QTStr(ESTIMATE_STR).arg(QString::number(int(memMB)))); - else + ui->advRBEstimate->setObjectName(""); + if (varRateControl) { + ui->advRBMegsMax->setVisible(false); + ui->advRBMegsMaxLabel->setVisible(false); + + if (memMB <= memMaxMB) { + ui->advRBEstimate->setText( + QTStr(ESTIMATE_STR) + .arg(QString::number(int(memMB)))); + } else { + ui->advRBEstimate->setText( + QTStr(ESTIMATE_TOO_LARGE_STR) + .arg(QString::number(int(memMB)), + QString::number(int(memMaxMB)))); + ui->advRBEstimate->setObjectName("warningLabel"); + } + } else { + ui->advRBMegsMax->setVisible(true); + ui->advRBMegsMaxLabel->setVisible(true); + ui->advRBMegsMax->setMaximum(memMaxMB); ui->advRBEstimate->setText(QTStr(ESTIMATE_UNKNOWN_STR)); + } ui->advReplayBufferFrame->setEnabled(!lossless && replayBufferEnabled); + ui->advRBEstimate->style()->polish(ui->advRBEstimate); ui->advReplayBuf->setEnabled(!lossless); UpdateAutomaticReplayBufferCheckboxes(); @@ -5134,11 +5301,11 @@ warning += "\n\n"; warning += QTStr("OutputWarnings.MP4Recording"); ui->autoRemux->setText( - QTStr("Basic.Settings.Advanced.AutoRemux") + " " + - QTStr("Basic.Settings.Advanced.AutoRemux.MP4")); + QTStr("Basic.Settings.Advanced.AutoRemux").arg("mp4") + + " " + QTStr("Basic.Settings.Advanced.AutoRemux.MP4")); } else { ui->autoRemux->setText( - QTStr("Basic.Settings.Advanced.AutoRemux")); + QTStr("Basic.Settings.Advanced.AutoRemux").arg("mp4")); } if (warning.isEmpty())
View file
obs-studio-28.1.2.tar.xz/UI/window-basic-settings.hpp -> obs-studio-29.0.0.tar.xz/UI/window-basic-settings.hpp
Changed
@@ -120,6 +120,7 @@ int pageIndex = 0; bool loading = true; bool forceAuthReload = false; + bool forceUpdateCheck = false; std::string savedTheme; int sampleRateIndex = 0; int channelIndex = 0; @@ -146,6 +147,7 @@ QString curQSVPreset; QString curNVENCPreset; QString curAMDPreset; + QString curAMDAV1Preset; QString curAdvStreamEncoder; QString curAdvRecordEncoder; @@ -218,12 +220,6 @@ EnableApplyButton(false); } -#ifdef _WIN32 - bool aeroWasDisabled = false; - QCheckBox *toggleAero = nullptr; - void ToggleDisableAero(bool checked); -#endif - void HookWidget(QWidget *widget, const char *signal, const char *slot); bool QueryChanges(); @@ -255,6 +251,7 @@ /* general */ void LoadLanguageList(); void LoadThemeList(); + void LoadBranchesList(); /* stream */ void InitStreamPage();
View file
obs-studio-28.1.2.tar.xz/UI/window-projector.cpp -> obs-studio-29.0.0.tar.xz/UI/window-projector.cpp
Changed
@@ -16,11 +16,12 @@ OBSProjector::OBSProjector(QWidget *widget, obs_source_t *source_, int monitor, ProjectorType type_) - : OBSQTDisplay(widget, Qt::Window), - source(source_), - removedSignal(obs_source_get_signal_handler(source), "remove", - OBSSourceRemoved, this) + : OBSQTDisplay(widget, Qt::Window), weakSource(OBSGetWeakRef(source_)) { + OBSSource source = GetSource(); + destroyedSignal.Connect(obs_source_get_signal_handler(source), + "destroy", OBSSourceDestroyed, this); + isAlwaysOnTop = config_get_bool(GetGlobalConfig(), "BasicWindow", "ProjectorAlwaysOnTop"); @@ -103,6 +104,7 @@ GetDisplay(), isMultiview ? OBSRenderMultiview : OBSRender, this); + OBSSource source = GetSource(); if (source) obs_source_dec_showing(source); @@ -157,7 +159,7 @@ return; OBSBasic *main = reinterpret_cast<OBSBasic *>(App()->GetMainWindow()); - OBSSource source = window->source; + OBSSource source = window->GetSource(); uint32_t targetCX; uint32_t targetCY; @@ -191,11 +193,11 @@ obs_source_dec_showing(source); obs_source_inc_showing(curSource); source = curSource; - window->source = source; + window->weakSource = OBSGetWeakRef(source); } } else if (window->type == ProjectorType::Preview && !main->IsPreviewProgramMode()) { - window->source = nullptr; + window->weakSource = nullptr; } if (source) @@ -206,7 +208,7 @@ endRegion(); } -void OBSProjector::OBSSourceRemoved(void *data, calldata_t *params) +void OBSProjector::OBSSourceDestroyed(void *data, calldata_t *params) { OBSProjector *window = reinterpret_cast<OBSProjector *>(data); QMetaObject::invokeMethod(window, "EscapeTriggered"); @@ -367,7 +369,7 @@ OBSSource OBSProjector::GetSource() { - return source; + return OBSGetStrongRef(weakSource); } ProjectorType OBSProjector::GetProjectorType() @@ -410,6 +412,7 @@ int monitor = sender()->property("monitor").toInt(); SetMonitor(monitor); + OBSSource source = GetSource(); UpdateProjectorTitle(QT_UTF8(obs_source_get_name(source))); } @@ -426,6 +429,7 @@ savedMonitor = -1; + OBSSource source = GetSource(); UpdateProjectorTitle(QT_UTF8(obs_source_get_name(source))); screen = nullptr; }
View file
obs-studio-28.1.2.tar.xz/UI/window-projector.hpp -> obs-studio-29.0.0.tar.xz/UI/window-projector.hpp
Changed
@@ -18,12 +18,12 @@ Q_OBJECT private: - OBSSource source; - OBSSignal removedSignal; + OBSWeakSourceAutoRelease weakSource; + OBSSignal destroyedSignal; static void OBSRenderMultiview(void *data, uint32_t cx, uint32_t cy); static void OBSRender(void *data, uint32_t cx, uint32_t cy); - static void OBSSourceRemoved(void *data, calldata_t *params); + static void OBSSourceDestroyed(void *data, calldata_t *params); void mousePressEvent(QMouseEvent *event) override; void mouseDoubleClickEvent(QMouseEvent *event) override;
View file
obs-studio-28.1.2.tar.xz/cmake/Modules/CompilerConfig.cmake -> obs-studio-29.0.0.tar.xz/cmake/Modules/CompilerConfig.cmake
Changed
@@ -67,7 +67,8 @@ /DUNICODE /D_UNICODE /D_CRT_SECURE_NO_WARNINGS - /D_CRT_NONSTDC_NO_WARNINGS) + /D_CRT_NONSTDC_NO_WARNINGS + /utf-8) add_link_options( "LINKER:/OPT:REF"
View file
obs-studio-28.1.2.tar.xz/cmake/Modules/FindGio.cmake -> obs-studio-29.0.0.tar.xz/cmake/Modules/FindGio.cmake
Changed
@@ -21,7 +21,7 @@ find_library( GIO_LIB - NAMES ${_GIO_LIBRARIES} gio-2.0 libgio-2.0 gio-unix-2.0 + NAMES gio-2.0 libgio-2.0 gio-unix-2.0 HINTS ${_GIO_LIBRARY_DIRS} PATHS /usr/lib /usr/local/lib /opt/local/lib /sw/lib)
View file
obs-studio-29.0.0.tar.xz/cmake/Modules/FindLibva.cmake
Added
@@ -0,0 +1,49 @@ +# * Try to find Libva, once done this will define +# +# * LIBVA_FOUND - system has Libva +# * LIBVA_INCLUDE_DIRS - the Libva include directory +# * LIBVA_LIBRARIES - the libraries needed to use Libva +# * LIBVA_DEFINITIONS - Compiler switches required for using Libva + +# Use pkg-config to get the directories and then use these values in the +# find_path() and find_library() calls + +find_package(PkgConfig QUIET) +if(PKG_CONFIG_FOUND) + pkg_check_modules(_LIBVA libva) +endif() + +find_path( + LIBVA_INCLUDE_DIR + NAMES va.h + HINTS ${_LIBVA_INCLUDE_DIRS} + PATHS /usr/include /usr/local/include /opt/local/include + PATH_SUFFIXES va/) + +find_library( + LIBVA_LIB + NAMES ${_LIBVA_LIBRARIES} libva + HINTS ${_LIBVA_LIBRARY_DIRS} + PATHS /usr/lib /usr/local/lib /opt/local/lib) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(Libva REQUIRED_VARS LIBVA_LIB + LIBVA_INCLUDE_DIR) +mark_as_advanced(LIBVA_INCLUDE_DIR LIBVA_LIB) + +if(LIBVA_FOUND) + set(LIBVA_INCLUDE_DIRS ${LIBVA_INCLUDE_DIR}) + set(LIBVA_LIBRARIES ${LIBVA_LIB}) + + if(NOT TARGET Libva::va) + if(IS_ABSOLUTE "${LIBVA_LIBRARIES}") + add_library(Libva::va UNKNOWN IMPORTED) + set_target_properties(Libva::va PROPERTIES IMPORTED_LOCATION + "${LIBVA_LIBRARIES}") + else() + add_library(Libva::va INTERFACE IMPORTED) + set_target_properties(Libva::va PROPERTIES IMPORTED_LIBNAME + "${LIBVA_LIBRARIES}") + endif() + endif() +endif()
View file
obs-studio-28.1.2.tar.xz/cmake/Modules/ObsDefaults_Linux.cmake -> obs-studio-29.0.0.tar.xz/cmake/Modules/ObsDefaults_Linux.cmake
Changed
@@ -49,7 +49,7 @@ └ libobs └ obs-plugins └ obs-studio - + # if(CMAKE_SIZEOF_VOID_P EQUAL 8) set(_ARCH_SUFFIX 64) @@ -114,14 +114,13 @@ set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_SOURCE_DIR}/UI/data/license/gplv2.txt") set(CPACK_PACKAGE_VERSION "${OBS_VERSION_CANONICAL}-${OBS_BUILD_NUMBER}") - set(CPACK_STRIP_FILES "bin/obs" "bin/obs-ffmpeg-mux") - set(CPACK_SOURCE_STRIP_FILES "") set(CPACK_PACKAGE_EXECUTABLES "obs") if(OS_LINUX AND NOT LINUX_PORTABLE) set(CPACK_GENERATOR "DEB") set(CPACK_DEBIAN_PACKAGE_SHLIBDEPS ON) set(CPACK_SET_DESTDIR ON) + set(CPACK_DEBIAN_DEBUGINFO_PACKAGE ON) elseif(OS_FREEBSD) option(ENABLE_CPACK_GENERATOR "Enable FreeBSD CPack generator (experimental)" OFF)
View file
obs-studio-28.1.2.tar.xz/cmake/Modules/VersionConfig.cmake -> obs-studio-29.0.0.tar.xz/cmake/Modules/VersionConfig.cmake
Changed
@@ -32,6 +32,13 @@ string(REPLACE "." ";" _CANONICAL_SPLIT ${_CANONICAL_SPLIT}) list(GET _CANONICAL_SPLIT 0 1 2 _OBS_VERSION_CANONICAL) string(REPLACE "." ";" _OBS_VERSION ${_OBS_VERSION}) + # Get 8-character commit hash without "g" prefix + foreach(VERSION_PART ${_CANONICAL_SPLIT}) + if(VERSION_PART MATCHES "^g") + string(SUBSTRING ${VERSION_PART}, 1, 8, OBS_COMMIT) + break() + endif() + endforeach() endif() endif() endif()
View file
obs-studio-28.1.2.tar.xz/deps/libcaption/caption/caption.h -> obs-studio-29.0.0.tar.xz/deps/libcaption/caption/caption.h
Changed
@@ -134,10 +134,6 @@ /*! \brief \param */ -#define CAPTION_FRAME_DUMP_BUF_SIZE 8192 -size_t caption_frame_dump_buffer(caption_frame_t* frame, utf8_char_t* buf); -void caption_frame_dump(caption_frame_t* frame); - #ifdef __cplusplus } #endif
View file
obs-studio-28.1.2.tar.xz/deps/libcaption/src/caption.c -> obs-studio-29.0.0.tar.xz/deps/libcaption/src/caption.c
Changed
@@ -403,57 +403,3 @@ return size; } -//////////////////////////////////////////////////////////////////////////////// -size_t caption_frame_dump_buffer(caption_frame_t* frame, utf8_char_t* buf) -{ - int r, c; - size_t bytes, total = 0; - bytes = sprintf(buf, " timestamp: %f\n row: %02d col: %02d roll-up: %d\n", - frame->timestamp, frame->state.row, frame->state.col, caption_frame_rollup(frame)); - total += bytes, buf += bytes; - bytes = sprintf(buf, " 00000000001111111111222222222233\t 00000000001111111111222222222233\n" - " 01234567890123456789012345678901\t 01234567890123456789012345678901\n" - " %s--------------------------------%s\t %s--------------------------------%s\n", - EIA608_CHAR_BOX_DRAWINGS_LIGHT_DOWN_AND_RIGHT, EIA608_CHAR_BOX_DRAWINGS_LIGHT_DOWN_AND_LEFT, - EIA608_CHAR_BOX_DRAWINGS_LIGHT_DOWN_AND_RIGHT, EIA608_CHAR_BOX_DRAWINGS_LIGHT_DOWN_AND_LEFT); - total += bytes; - buf += bytes; - - for (r = 0; r < SCREEN_ROWS; ++r) { - bytes = sprintf(buf, "%02d%s", r, EIA608_CHAR_VERTICAL_LINE); - total += bytes, buf += bytes; - - // front buffer - for (c = 0; c < SCREEN_COLS; ++c) { - caption_frame_cell_t* cell = frame_buffer_cell(&frame->front, r, c); - bytes = utf8_char_copy(buf, (!cell || 0 == cell->data0) ? EIA608_CHAR_SPACE : &cell->data0); - total += bytes, buf += bytes; - } - - bytes = sprintf(buf, "%s\t%02d%s", EIA608_CHAR_VERTICAL_LINE, r, EIA608_CHAR_VERTICAL_LINE); - total += bytes, buf += bytes; - - // back buffer - for (c = 0; c < SCREEN_COLS; ++c) { - caption_frame_cell_t* cell = frame_buffer_cell(&frame->back, r, c); - bytes = utf8_char_copy(buf, (!cell || 0 == cell->data0) ? EIA608_CHAR_SPACE : &cell->data0); - total += bytes, buf += bytes; - } - - bytes = sprintf(buf, "%s\n", EIA608_CHAR_VERTICAL_LINE); - total += bytes, buf += bytes; - } - - bytes = sprintf(buf, " %s--------------------------------%s\t %s--------------------------------%s\n", - EIA608_CHAR_BOX_DRAWINGS_LIGHT_UP_AND_RIGHT, EIA608_CHAR_BOX_DRAWINGS_LIGHT_UP_AND_LEFT, - EIA608_CHAR_BOX_DRAWINGS_LIGHT_UP_AND_RIGHT, EIA608_CHAR_BOX_DRAWINGS_LIGHT_UP_AND_LEFT); - total += bytes, buf += bytes; - return total; -} - -void caption_frame_dump(caption_frame_t* frame) -{ - utf8_char_t buffCAPTION_FRAME_DUMP_BUF_SIZE; - caption_frame_dump_buffer(frame, buff); - fprintf(stderr, "%s\n", buff); -}
View file
obs-studio-28.1.2.tar.xz/deps/libcaption/src/utf8.c -> obs-studio-29.0.0.tar.xz/deps/libcaption/src/utf8.c
Changed
@@ -220,7 +220,10 @@ } } - data*size = 0; + if (data) { + data*size = 0; + } + return data; }
View file
obs-studio-28.1.2.tar.xz/deps/media-playback/media-playback/media.c -> obs-studio-29.0.0.tar.xz/deps/media-playback/media-playback/media.c
Changed
@@ -353,6 +353,12 @@ struct mp_decode *d = &m->a; struct obs_source_audio audio = {0}; AVFrame *f = d->frame; + int channels; +#if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(59, 19, 100) + channels = f->channels; +#else + channels = f->ch_layout.nb_channels; +#endif if (!mp_media_can_play_frame(m, d)) return; @@ -365,7 +371,7 @@ audio.datai = f->datai; audio.samples_per_sec = f->sample_rate * m->speed / 100; - audio.speakers = convert_speaker_layout(f->channels); + audio.speakers = convert_speaker_layout(channels); audio.format = convert_sample_format(f->format); audio.frames = f->nb_samples;
View file
obs-studio-28.1.2.tar.xz/deps/obs-scripting/obs-scripting-python-import.c -> obs-studio-29.0.0.tar.xz/deps/obs-scripting/obs-scripting-python-import.c
Changed
@@ -71,9 +71,9 @@ char tempPATH_MAX; - sprintf(cur_version, VERSION_PATTERN, PY_MAJOR_VERSION_MAX, - PY_MINOR_VERSION_MAX); - sprintf(temp, FILE_PATTERN, cur_version); + snprintf(cur_version, sizeof(cur_version), VERSION_PATTERN, + PY_MAJOR_VERSION_MAX, PY_MINOR_VERSION_MAX); + snprintf(temp, sizeof(temp), FILE_PATTERN, cur_version); dstr_cat(&lib_candidate_path, temp); @@ -87,10 +87,10 @@ break; } - sprintf(cur_version, VERSION_PATTERN, PY_MAJOR_VERSION_MAX, - minor_version); - sprintf(next_version, VERSION_PATTERN, PY_MAJOR_VERSION_MAX, - --minor_version); + snprintf(cur_version, sizeof(cur_version), VERSION_PATTERN, + PY_MAJOR_VERSION_MAX, minor_version); + snprintf(next_version, sizeof(next_version), VERSION_PATTERN, + PY_MAJOR_VERSION_MAX, --minor_version); dstr_replace(&lib_candidate_path, cur_version, next_version); } while (minor_version > 5);
View file
obs-studio-28.1.2.tar.xz/deps/obs-scripting/obs-scripting-python.c -> obs-studio-29.0.0.tar.xz/deps/obs-scripting/obs-scripting-python.c
Changed
@@ -1666,8 +1666,8 @@ if (python_path && *python_path) { #ifdef __APPLE__ char tempPATH_MAX; - sprintf(temp, "%s/Python.framework/Versions/Current", - python_path); + snprintf(temp, sizeof(temp), + "%s/Python.framework/Versions/Current", python_path); os_utf8_to_wcs(temp, 0, home_path, PATH_MAX); Py_SetPythonHome(home_path); #else
View file
obs-studio-28.1.2.tar.xz/docs/sphinx/reference-core.rst -> obs-studio-29.0.0.tar.xz/docs/sphinx/reference-core.rst
Changed
@@ -363,7 +363,8 @@ .. function:: obs_data_t *obs_save_source(obs_source_t *source) - :return: A new reference to a source's saved data + :return: A new reference to a source's saved data. Use + :c:func:`obs_data_release()` to release it when complete. --------------------- @@ -478,13 +479,19 @@ .. function:: void obs_set_master_volume(float volume) - Sets the master user volume. + No-op, only exists to keep ABI compatibility. + + .. deprecated:: 29.0 --------------------- .. function:: float obs_get_master_volume(void) - :return: The master user volume + No-op, only exists to keep ABI compatibility. + + :return: Always returns 1 + + .. deprecated:: 29.0 --------------------- @@ -557,7 +564,8 @@ .. function:: signal_handler_t *obs_get_signal_handler(void) - :return: The primary obs signal handler + :return: The primary obs signal handler. Should not be manually freed, + as its lifecycle is managed by libobs. See :ref:`core_signal_handler_reference` for more information on core signals. @@ -566,7 +574,8 @@ .. function:: proc_handler_t *obs_get_proc_handler(void) - :return: The primary obs procedure handler + :return: The primary obs procedure handler. Should not be manually freed, + as its lifecycle is managed by libobs. .. _core_signal_handler_reference: @@ -587,6 +596,10 @@ Called when a source has been removed (:c:func:`obs_source_remove()` has been called on the source). +**source_update** (ptr source) + + Called when a source's settings have been updated. + **source_save** (ptr source) Called when a source is being saved. @@ -639,10 +652,6 @@ Called when :c:func:`obs_set_output_source()` has been called. -**master_volume** (in out float volume) - - Called when the master volume has changed. - **hotkey_layout_change** () Called when the hotkey layout has changed.
View file
obs-studio-28.1.2.tar.xz/docs/sphinx/reference-encoders.rst -> obs-studio-29.0.0.tar.xz/docs/sphinx/reference-encoders.rst
Changed
@@ -332,7 +332,7 @@ .. function:: obs_encoder_t *obs_encoder_get_ref(obs_encoder_t *encoder) Returns an incremented reference if still valid, otherwise returns - *NULL*. + *NULL*. Release with :c:func:`obs_encoder_release()`. --------------------- @@ -437,7 +437,8 @@ .. function:: obs_data_t *obs_encoder_defaults(const char *id) obs_data_t *obs_encoder_get_defaults(const obs_encoder_t *encoder) - :return: An incremented reference to the encoder's default settings + :return: An incremented reference to the encoder's default settings. + Release with :c:func:`obs_data_release()`. --------------------- @@ -461,19 +462,22 @@ .. function:: obs_data_t *obs_encoder_get_settings(const obs_encoder_t *encoder) - :return: An incremented reference to the encoder's settings + :return: An incremented reference to the encoder's settings. Release with + :c:func:`obs_data_release()`. --------------------- .. function:: signal_handler_t *obs_encoder_get_signal_handler(const obs_encoder_t *encoder) - :return: The signal handler of the encoder + :return: The signal handler of the encoder. Should not be manually freed, + as its lifecycle is managed by libobs. --------------------- .. function:: proc_handler_t *obs_encoder_get_proc_handler(const obs_encoder_t *encoder) - :return: The procedure handler of the encoder + :return: The procedure handler of the encoder. Should not be manually freed, + as its lifecycle is managed by libobs. ---------------------
View file
obs-studio-28.1.2.tar.xz/docs/sphinx/reference-frontend-api.rst -> obs-studio-29.0.0.tar.xz/docs/sphinx/reference-frontend-api.rst
Changed
@@ -79,7 +79,7 @@ - **OBS_FRONTEND_EVENT_TRANSITION_DURATION_CHANGED** Triggered when the transition duration has been changed by the - user. + user. - **OBS_FRONTEND_EVENT_TBAR_VALUE_CHANGED** @@ -178,6 +178,17 @@ Triggered when the virtual camera is stopped. + - **OBS_FRONTEND_EVENT_THEME_CHANGED** + + Triggered when the theme is changed. + + .. versionadded:: 29.0.0 + + - **OBS_FRONTEND_EVENT_SCREENSHOT_TAKEN** + + Triggered when a screenshot is taken. + + .. versionadded:: 29.0.0 .. struct:: obs_frontend_source_list @@ -259,7 +270,8 @@ .. function:: obs_source_t *obs_frontend_get_current_scene(void) - :return: A new reference to the currently active scene + :return: A new reference to the currently active scene. Release with + :c:func:`obs_source_release()`. --------------------------------------- @@ -280,7 +292,8 @@ .. function:: obs_source_t *obs_frontend_get_current_transition(void) - :return: A new reference to the currently active transition + :return: A new reference to the currently active transition. + Release with :c:func:`obs_source_release()`. --------------------------------------- @@ -605,19 +618,22 @@ .. function:: obs_output_t *obs_frontend_get_streaming_output(void) - :return: A new reference to the current streaming output + :return: A new reference to the current streaming output. + Release with :c:func:`obs_output_release()`. --------------------------------------- .. function:: obs_output_t *obs_frontend_get_recording_output(void) - :return: A new reference to the current srecording output + :return: A new reference to the current recording output. + Release with :c:func:`obs_output_release()`. --------------------------------------- .. function:: obs_output_t *obs_frontend_get_replay_buffer_output(void) - :return: A new reference to the current replay buffer output + :return: A new reference to the current replay buffer output. + Release with :c:func:`obs_output_release()`. --------------------------------------- @@ -643,7 +659,8 @@ .. function:: obs_service_t *obs_frontend_get_streaming_service(void) - :return: A new reference to the current streaming service object + :return: The current streaming service object. Does not increment the + reference. --------------------------------------- @@ -677,7 +694,8 @@ .. function:: obs_source_t *obs_frontend_get_current_preview_scene(void) :return: A new reference to the current preview scene if studio mode - is active, or *NULL* if studio mode is not active. + is active, or *NULL* if studio mode is not active. Release + with :c:func:`obs_source_release()`. --------------------------------------- @@ -721,7 +739,8 @@ .. function:: obs_output_t *obs_frontend_get_virtualcam_output(void) - :return: A new reference to the current virtual camera output + :return: A new reference to the current virtual camera output. + Release with :c:func:`obs_output_release()`. --------------------------------------- @@ -785,3 +804,37 @@ .. function:: const char *obs_frontend_get_locale_string(const char *string) :return: Gets the frontend translation of a given string. + +--------------------------------------- + +.. function:: bool obs_frontend_is_theme_dark(void) + + :return: Checks if the current theme is dark or light. + + .. versionadded:: 29.0.0 + +--------------------------------------- + +.. function:: char *obs_frontend_get_last_recording(void) + + :return: The file path of the last recording. Free with :c:func:`bfree()` + + .. versionadded:: 29.0.0 + +--------------------------------------- + +.. function:: char *obs_frontend_get_last_screenshot(void) + + :return: The file path of the last screenshot taken. Free with + :c:func:`bfree()` + + .. versionadded:: 29.0.0 + +--------------------------------------- + +.. function:: char *obs_frontend_get_last_replay(void) + + :return: The file path of the last replay buffer saved. Free with + :c:func:`bfree()` + + .. versionadded:: 29.0.0
View file
obs-studio-28.1.2.tar.xz/docs/sphinx/reference-libobs-callback.rst -> obs-studio-29.0.0.tar.xz/docs/sphinx/reference-libobs-callback.rst
Changed
@@ -22,7 +22,9 @@ .. function:: void calldata_free(calldata_t *data) - Frees a calldata structure. + Frees a calldata structure. Should only be used if :c:func:`calldata_init()` + was used. If the object is received as a callback parameter, this function + should not be used. :param data: Calldata structure @@ -110,7 +112,9 @@ .. function:: void *calldata_ptr(const calldata_t *data, const char *name) - Gets a pointer parameter. + Gets a pointer parameter. For example, :ref:`core_signal_handler_reference` + that have ``ptr source`` as a parameter requires this function to get the + pointer, which can be casted to :c:type:`obs_source_t`. Does not have to be freed. :param data: Calldata structure :param name: Parameter name @@ -188,11 +192,14 @@ .. function:: void signal_handler_connect(signal_handler_t *handler, const char *signal, signal_callback_t callback, void *data) - Connect a callback to a signal on a signal handler. + Connects a callback to a signal on a signal handler. Does nothing + if the combination of ``signal``, ``callback``, and ``data`` + is already connected to the handler. :param handler: Signal handler object + :param signal: Name of signal to handle :param callback: Signal callback - :param data: Private data passed the callback + :param data: Private data passed to the callback For scripting, use :py:func:`signal_handler_connect`. @@ -200,23 +207,29 @@ .. function:: void signal_handler_connect_ref(signal_handler_t *handler, const char *signal, signal_callback_t callback, void *data) - Connect a callback to a signal on a signal handler, and increments + Connects a callback to a signal on a signal handler, and increments the handler's internal reference counter, preventing it from being - destroyed until the signal has been disconnected. + destroyed until the signal has been disconnected. Even if the combination of + ``signal``, ``callback``, and ``data`` is already connected to the handler, + the reference counter is still incremented. :param handler: Signal handler object + :param signal: Name of signal to handle :param callback: Signal callback - :param data: Private data passed the callback + :param data: Private data passed to the callback --------------------- .. function:: void signal_handler_disconnect(signal_handler_t *handler, const char *signal, signal_callback_t callback, void *data) - Disconnects a callback from a signal on a signal handler. + Disconnects a callback from a signal on a signal handler. Does nothing + if the combination of ``signal``, ``callback``, and ``data`` + is not yet connected to the handler. :param handler: Signal handler object + :param signal: Name of signal that was handled :param callback: Signal callback - :param data: Private data passed the callback + :param data: Private data passed to the callback For scripting, use :py:func:`signal_handler_disconnect`.
View file
obs-studio-28.1.2.tar.xz/docs/sphinx/reference-libobs-util-platform.rst -> obs-studio-29.0.0.tar.xz/docs/sphinx/reference-libobs-util-platform.rst
Changed
@@ -447,6 +447,14 @@ --------------------- +.. function:: uint64_t os_get_sys_total_size(void) + + Returns the amount of memory installed. + + .. versionadded:: 29.0.0 + +--------------------- + .. struct:: os_proc_memory_usage Memory usage structure. @@ -483,7 +491,8 @@ .. function:: bool os_get_emulation_status(void) - Returns true if the current process is a x64 binary and is being emulated or translated - by the host operating system. On macOS, it returns true when a x64 binary is - being translated by Rosetta and running on Apple Silicon Macs. This function is not yet - implemented on Windows and Linux and will always return false on those platforms. + Returns true if the current process is an x64 binary and is being emulated or translated + by the host operating system. On macOS, it returns true when an x64 binary is + being translated by Rosetta and running on Apple Silicon Macs. On Windows, it + returns true when an x64 binary is being emulated on Windows ARM64 PCs. On all other + platforms, it will always returns false.
View file
obs-studio-28.1.2.tar.xz/docs/sphinx/reference-outputs.rst -> obs-studio-29.0.0.tar.xz/docs/sphinx/reference-outputs.rst
Changed
@@ -345,7 +345,7 @@ .. function:: obs_output_t *obs_output_get_ref(obs_output_t *output) Returns an incremented reference if still valid, otherwise returns - *NULL*. + *NULL*. Release with :c:func:`obs_output_release()`. --------------------- @@ -443,7 +443,8 @@ .. function:: obs_data_t *obs_output_defaults(const char *id) - :return: An incremented reference to the output's default settings + :return: An incremented reference to the output's default settings. + Release with :c:func:`obs_data_release()`. --------------------- @@ -488,19 +489,22 @@ .. function:: obs_data_t *obs_output_get_settings(const obs_output_t *output) - :return: An incremented reference to the output's settings + :return: An incremented reference to the output's settings. Release with + :c:func:`obs_data_release()`. --------------------- .. function:: signal_handler_t *obs_output_get_signal_handler(const obs_output_t *output) - :return: The signal handler of the output + :return: The signal handler of the output. Should not be manually freed, + as its lifecycle is managed by libobs. --------------------- .. function:: proc_handler_t *obs_output_get_proc_handler(const obs_output_t *output) - :return: The procedure handler of the output + :return: The procedure handler of the output. Should not be manually freed, + as its lifecycle is managed by libobs. ---------------------
View file
obs-studio-28.1.2.tar.xz/docs/sphinx/reference-properties.rst -> obs-studio-29.0.0.tar.xz/docs/sphinx/reference-properties.rst
Changed
@@ -220,7 +220,8 @@ .. function:: obs_property_t *obs_properties_add_color(obs_properties_t *props, const char *name, const char *description) - Adds a color property without alpha. + Adds a color property without alpha (stored internally with an alpha value of 255). + The color can be retrieved from an :c:type:`obs_data_t` object by using :c:func:`obs_data_get_int()`. :param name: Setting identifier string :param description: Localized name shown to user @@ -230,7 +231,8 @@ .. function:: obs_property_t *obs_properties_add_color_alpha(obs_properties_t *props, const char *name, const char *description) - Adds a color property with alpha. + Adds a color property with alpha. The color can be retrieved from an + :c:type:`obs_data_t` object by using :c:func:`obs_data_get_int()`. :param name: Setting identifier string :param description: Localized name shown to user @@ -266,7 +268,8 @@ .. function:: obs_property_t *obs_properties_add_font(obs_properties_t *props, const char *name, const char *description) - Adds a font property. + Adds a font property. The font can be retrieved from an :c:type:`obs_data_t` + object by using :c:func:`obs_data_get_obj()`. :param name: Setting identifier string :param description: Localized name shown to user @@ -276,7 +279,8 @@ .. function:: obs_property_t *obs_properties_add_editable_list(obs_properties_t *props, const char *name, const char *description, enum obs_editable_list_type type, const char *filter, const char *default_path) - Adds a list in which the user can add/insert/remove items. + Adds a list in which the user can add/insert/remove items. The items can be + retrieved from an :c:type:`obs_data_t` object by using :c:func:`obs_data_get_array()`. :param name: Setting identifier string :param description: Localized name shown to user @@ -576,7 +580,9 @@ void obs_property_set_modified_callback2(obs_property_t *p, obs_property_modified2_t modified2, void *priv) Allows the ability to change the properties depending on what - settings are used by the user. + settings are used by the user. The callback should return ``true`` + if the property widgets need to be refreshed due to changes to the + property layout. Relevant data types used with these functions: @@ -649,36 +655,60 @@ Adds a string to a string list. + :param name: Localized name shown to user + :param val: The actual string value stored and will be returned by :c:func:`obs_data_get_string` + :returns: The index of the list item. + --------------------- .. function:: size_t obs_property_list_add_int(obs_property_t *p, const char *name, long long val) Adds an integer to a integer list. + :param name: Localized name shown to user + :param val: The actual int value stored and will be returned by :c:func:`obs_data_get_int` + :returns: The index of the list item. + --------------------- .. function:: size_t obs_property_list_add_float(obs_property_t *p, const char *name, double val) Adds a floating point to a floating point list. + :param name: Localized name shown to user + :param val: The actual float value stored and will be returned by :c:func:`obs_data_get_double` + :returns: The index of the list item. + --------------------- .. function:: void obs_property_list_insert_string(obs_property_t *p, size_t idx, const char *name, const char *val) Inserts a string in to a string list. + :param idx: The index of the list item + :param name: Localized name shown to user + :param val: The actual string value stored and will be returned by :c:func:`obs_data_get_string` + --------------------- .. function:: void obs_property_list_insert_int(obs_property_t *p, size_t idx, const char *name, long long val) Inserts an integer in to an integer list. + :param idx: The index of the list item + :param name: Localized name shown to user + :param val: The actual int value stored and will be returned by :c:func:`obs_data_get_int` + --------------------- .. function:: void obs_property_list_insert_float(obs_property_t *p, size_t idx, const char *name, double val) Inserts a floating point in to a floating point list. + :param idx: The index of the list item. + :param name: Localized name shown to user + :param val: The actual float value stored and will be returned by :c:func:`obs_data_get_double` + --------------------- .. function:: void obs_property_list_item_disable(obs_property_t *p, size_t idx, bool disabled)
View file
obs-studio-28.1.2.tar.xz/docs/sphinx/reference-scenes.rst -> obs-studio-29.0.0.tar.xz/docs/sphinx/reference-scenes.rst
Changed
@@ -208,7 +208,7 @@ .. function:: obs_scene_t *obs_scene_get_ref(obs_scene_t *scene) Returns an incremented reference if still valid, otherwise returns - *NULL*. + *NULL*. Release with :c:func:`obs_scene_release()`. --------------------- @@ -549,7 +549,8 @@ :return: An incremented reference to the private settings of the scene item. Allows the front-end to set custom information - which is saved with the scene item + which is saved with the scene item. Release with + :c:func:`obs_data_release()`. ---------------------
View file
obs-studio-28.1.2.tar.xz/docs/sphinx/reference-services.rst -> obs-studio-29.0.0.tar.xz/docs/sphinx/reference-services.rst
Changed
@@ -200,7 +200,7 @@ .. function:: obs_service_t *obs_service_get_ref(obs_service_t *service) Returns an incremented reference if still valid, otherwise returns - *NULL*. + *NULL*. Release with :c:func:`obs_service_release()`. --------------------- @@ -236,7 +236,8 @@ .. function:: obs_data_t *obs_service_defaults(const char *id) - :return: An incremented reference to the service's default settings + :return: An incremented reference to the service's default settings. + Release with :c:func:`obs_data_release()`. --------------------- @@ -254,7 +255,8 @@ .. function:: obs_data_t *obs_service_get_settings(const obs_service_t *service) - :return: An incremented reference to the service's settings + :return: An incremented reference to the service's settings. Release with + :c:func:`obs_data_release()`. ---------------------
View file
obs-studio-28.1.2.tar.xz/docs/sphinx/reference-settings.rst -> obs-studio-29.0.0.tar.xz/docs/sphinx/reference-settings.rst
Changed
@@ -25,7 +25,8 @@ .. function:: obs_data_t *obs_data_create() - :return: A new reference to a data object. + :return: A new reference to a data object. Release with + :c:func:`obs_data_release()`. --------------------- @@ -34,7 +35,8 @@ Creates a data object from a Json string. :param json_string: Json string - :return: A new reference to a data object + :return: A new reference to a data object. Release with + :c:func:`obs_data_release()`. --------------------- @@ -43,7 +45,8 @@ Creates a data object from a Json file. :param json_file: Json file path - :return: A new reference to a data object + :return: A new reference to a data object. Release with + :c:func:`obs_data_release()`. --------------------- @@ -54,7 +57,8 @@ :param json_file: Json file path :param backup_ext: Backup file extension - :return: A new reference to a data object + :return: A new reference to a data object. Release with + :c:func:`obs_data_release()`. --------------------- @@ -176,13 +180,15 @@ .. function:: obs_data_t *obs_data_get_obj(obs_data_t *data, const char *name) - :return: An incremented reference to a data object. + :return: An incremented reference to a data object. Release with + :c:func:`obs_data_release()`. --------------------- .. function:: obs_data_array_t *obs_data_get_array(obs_data_t *data, const char *name) - :return: An incremented reference to a data array object. + :return: An incremented reference to a data array object. Release + with :c:func:`obs_data_array_release()`. --------------------- @@ -224,7 +230,8 @@ .. function:: void obs_data_set_default_obj(obs_data_t *data, const char *name, obs_data_t *obj) obs_data_t *obs_data_get_default_obj(obs_data_t *data, const char *name) - :return: An incremented reference to a data object. + :return: An incremented reference to a data object. Release with + :c:func:`obs_data_release()`. ---------------------- @@ -262,7 +269,8 @@ .. function:: void obs_data_set_autoselect_obj(obs_data_t *data, const char *name, obs_data_t *obj) obs_data_t *obs_data_get_autoselect_obj(obs_data_t *data, const char *name) - :return: An incremented reference to a data object. + :return: An incremented reference to a data object. Release with + :c:func:`obs_data_release()`. --------------------- @@ -272,7 +280,8 @@ .. function:: obs_data_array_t *obs_data_array_create() - :return: A new reference to a data array object. + :return: A new reference to a data array object. Release + with :c:func:`obs_data_array_release()`. --------------------- @@ -291,7 +300,7 @@ .. function:: obs_data_t *obs_data_array_item(obs_data_array_t *array, size_t idx) :return: An incremented reference to the data object associated with - this array entry. + this array entry. Release with :c:func:`obs_data_release()`. ---------------------
View file
obs-studio-28.1.2.tar.xz/docs/sphinx/reference-sources.rst -> obs-studio-29.0.0.tar.xz/docs/sphinx/reference-sources.rst
Changed
@@ -31,6 +31,14 @@ Unique string identifier for the source (required). +.. member:: uint32_t version + + Source version (optional). + + This is used when a source's implementation is significantly + modified and the previous version is deprecated, but is kept to + prevent old sources from breaking. + .. member:: enum obs_source_type obs_source_info.type Type of source. @@ -502,6 +510,10 @@ - **OBS_MEDIA_STATE_ENDED** - Ended - **OBS_MEDIA_STATE_ERROR** - Error +.. member:: obs_missing_files_t *(*missing_files)(void *data) + + Called to get the missing files of the source. + .. member:: enum gs_color_space (*obs_source_info.video_get_color_space)(void *data, size_t count, const enum gs_color_space *preferred_spaces) Returns the color space of the source. Assume GS_CS_SRGB if not @@ -531,6 +543,12 @@ Called when the :c:func:`obs_source_remove()` function is called on the source. +**update** (ptr source) + + Called when the source's settings have been updated. + + .. versionadded:: 29.0.0 + **save** (ptr source) Called when the source is being saved. @@ -692,7 +710,7 @@ Creates a source of the specified type with the specified settings. The "source" context is used for anything related to presenting - or modifying video/audio. Use obs_source_release to release it. + or modifying video/audio. Use :c:func:`obs_source_release` to release it. :param id: The source type string identifier :param name: The desired name of the source. If this is @@ -732,7 +750,8 @@ Duplicates a source. If the source has the OBS_SOURCE_DO_NOT_DUPLICATE output flag set, this only returns a - new reference to the same source. + new reference to the same source. Either way, + release with :c:func:`obs_source_release`. :param source: The source to duplicate :param desired_name: The desired name of the new source. If this is @@ -756,7 +775,7 @@ .. function:: obs_source_t *obs_source_get_ref(obs_source_t *source) Returns an incremented reference if still valid, otherwise returns - *NULL*. + *NULL*. Use :c:func:`obs_source_release` to release it. --------------------- @@ -937,15 +956,35 @@ --------------------- +.. function:: bool obs_source_is_scene(const obs_source_t *source) + + :return: *true* if the source is a scene + +--------------------- + +.. function:: bool obs_source_is_group(const obs_source_t *source) + + :return: *true* if the source is a group + +--------------------- + .. function:: const char *obs_source_get_id(const obs_source_t *source) - :return: The source's type identifier string + :return: The source's type identifier string. If the source is versioned, + "_vN" is appended at the end, where "N" is the source's version. + + --------------------- + +.. function:: const char *obs_source_get_unversioned_id(const obs_source_t *source) + + :return: The source's unversioned type identifier string. --------------------- .. function:: signal_handler_t *obs_source_get_signal_handler(const obs_source_t *source) - :return: The source's signal handler + :return: The source's signal handler. Should not be manually freed, + as its lifecycle is managed by libobs. See the :ref:`source_signal_handler_reference` for more information on signals that are available for sources. @@ -954,7 +993,8 @@ .. function:: proc_handler_t *obs_source_get_proc_handler(const obs_source_t *source) - :return: The procedure handler for a source + :return: The procedure handler for a source. Should not be manually freed, + as its lifecycle is managed by libobs. --------------------- @@ -995,7 +1035,7 @@ .. function:: void obs_source_set_audio_mixers(obs_source_t *source, uint32_t mixers) uint32_t obs_source_get_audio_mixers(const obs_source_t *source) - Sets/gets the audio mixer channels that a source outputs to, + Sets/gets the audio mixer channels (i.e. audio tracks) that a source outputs to, depending on what bits are set. Audio mixers allow filtering specific using multiple audio encoders to mix different sources together depending on what mixer channel they're set to. @@ -1116,6 +1156,14 @@ --------------------- +.. function:: void obs_source_copy_single_filter(obs_source_t *dst, obs_source_t *filter) + + Copies the filter from the source to the destination. If a filter by the + same name already exists in the destination source, the newer filter + will be given a unique name. + +--------------------- + .. function:: size_t obs_source_filter_count(const obs_source_t *source) Returns the number of filters the source has. @@ -1182,7 +1230,8 @@ .. function:: obs_data_t *obs_source_get_private_settings(obs_source_t *item) Gets private front-end settings data. This data is saved/loaded - automatically. Returns an incremented reference. + automatically. Returns an incremented reference. Use :c:func:`obs_data_release()` + to release it. --------------------- @@ -1221,6 +1270,77 @@ --------------------- +.. function:: enum obs_icon_type obs_source_get_icon_type(const char *id) + + Calls the :c:member:`obs_source_info.icon_type` to get the icon type. + +--------------------- + +.. function:: void obs_source_media_play_pause(obs_source_t *source, bool pause) + + Calls the :c:member:`obs_source_info.media_play_pause` to pause or play media. + +--------------------- + +.. function:: void obs_source_media_restart(obs_source_t *source) + + Calls the :c:member:`obs_source_info.media_restart` to restart the media. + +--------------------- + +.. function:: void obs_source_media_stop(obs_source_t *source) + + Calls the :c:member:`obs_source_info.media_stop` to stop the media. + +--------------------- + +.. function:: void obs_source_media_next(obs_source_t *source) + + Calls the :c:member:`obs_source_info.media_next` to go to the next media. + +--------------------- + +.. function:: void obs_source_media_previous(obs_source_t *source) + + Calls the :c:member:`obs_source_info.media_previous` to go to the previous media. + +--------------------- + +.. function:: int64_t obs_source_media_get_duration(obs_source_t *source) + + Calls the :c:member:`obs_source_info.media_get_duration` to + get the media duration in milliseconds. + +--------------------- + +.. function:: int64_t obs_source_media_get_time(obs_source_t *source) + void obs_source_media_set_time(obs_source_t *source, int64_t ms) + + Calls the :c:member:`obs_source_info.media_get_time` or + :c:member:`obs_source_info.media_set_time` to get/set the + current time (in milliseconds) of the media. Will return 0 + for non-media sources. + +--------------------- + +.. function:: enum obs_media_state obs_source_media_get_state(obs_source_t *source) + + Calls the :c:member:`obs_source_info.media_get_state` to get the state of the media. + +--------------------- + +.. function:: void obs_source_media_started(obs_source_t *source) + + Emits a **media_started** signal. + +--------------------- + +.. function:: void obs_source_media_ended(obs_source_t *source) + + Emits a **media_ended** signal. + +--------------------- + Functions used by sources ------------------------- @@ -1493,7 +1613,8 @@ :param target: | OBS_TRANSITION_SOURCE_A - Source being transitioned from, or the current source if not transitioning | OBS_TRANSITION_SOURCE_B - Source being transitioned to :return: An incremented reference to the source or destination - sources of the transition + sources of the transition. Use :c:func:`obs_source_release` + to release it. --------------------- @@ -1506,7 +1627,7 @@ .. function:: obs_source_t *obs_transition_get_active_source(obs_source_t *transition) :return: An incremented reference to the currently active source of - the transition + the transition. Use :c:func:`obs_source_release` to release it. ---------------------
View file
obs-studio-28.1.2.tar.xz/libobs-d3d11/d3d11-subsystem.cpp -> obs-studio-29.0.0.tar.xz/libobs-d3d11/d3d11-subsystem.cpp
Changed
@@ -66,7 +66,8 @@ next->prev_next = prev_next; } -static bool screen_supports_hdr(gs_device_t *device, HMONITOR hMonitor) +static gs_monitor_color_info get_monitor_color_info(gs_device_t *device, + HMONITOR hMonitor) { IDXGIFactory1 *factory1 = device->factory; if (!factory1->IsCurrent()) { @@ -75,7 +76,8 @@ device->monitor_to_hdr.clear(); } - for (const std::pair<HMONITOR, bool> &pair : device->monitor_to_hdr) { + for (const std::pair<HMONITOR, gs_monitor_color_info> &pair : + device->monitor_to_hdr) { if (pair.first == hMonitor) return pair.second; } @@ -96,15 +98,19 @@ const bool hdr = desc1.ColorSpace == DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020; - device->monitor_to_hdr.emplace_back( - hMonitor, hdr); - return hdr; + return device->monitor_to_hdr + .emplace_back( + hMonitor, + gs_monitor_color_info( + hdr, + desc1.BitsPerColor)) + .second; } } } } - return false; + return gs_monitor_color_info(false, 8); } static enum gs_color_space get_next_space(gs_device_t *device, HWND hwnd, @@ -115,8 +121,12 @@ const HMONITOR hMonitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST); if (hMonitor) { - if (screen_supports_hdr(device, hMonitor)) + const gs_monitor_color_info info = + get_monitor_color_info(device, hMonitor); + if (info.hdr) next_space = GS_CS_709_SCRGB; + else if (info.bits_per_color > 8) + next_space = GS_CS_SRGB_16F; } } @@ -126,7 +136,14 @@ static enum gs_color_format get_swap_format_from_space(gs_color_space space, gs_color_format sdr_format) { - return (space == GS_CS_709_SCRGB) ? GS_RGBA16F : sdr_format; + gs_color_format format = sdr_format; + switch (space) { + case GS_CS_SRGB_16F: + case GS_CS_709_SCRGB: + format = GS_RGBA16F; + } + + return format; } static inline enum gs_color_space @@ -313,7 +330,8 @@ int ver = 49; while (ver > 30) { - sprintf(d3dcompiler, "D3DCompiler_%02d.dll", ver); + snprintf(d3dcompiler, sizeof(d3dcompiler), + "D3DCompiler_%02d.dll", ver); HMODULE module = LoadLibraryA(d3dcompiler); if (module) { @@ -346,45 +364,6 @@ throw UnsupportedHWError("Failed to create DXGIFactory", hr); } -#define VENDOR_ID_INTEL 0x8086 -#define IGPU_MEM (512 * 1024 * 1024) - -void gs_device::ReorderAdapters(uint32_t &adapterIdx) -{ - std::vector<uint32_t> adapterOrder; - ComPtr<IDXGIAdapter> adapter; - DXGI_ADAPTER_DESC desc; - uint32_t iGPUIndex = 0; - bool hasIGPU = false; - bool hasDGPU = false; - int idx = 0; - - while (SUCCEEDED(factory->EnumAdapters(idx, &adapter))) { - if (SUCCEEDED(adapter->GetDesc(&desc))) { - if (desc.VendorId == VENDOR_ID_INTEL) { - if (desc.DedicatedVideoMemory <= IGPU_MEM) { - hasIGPU = true; - iGPUIndex = (uint32_t)idx; - } else { - hasDGPU = true; - } - } - } - - adapterOrder.push_back((uint32_t)idx++); - } - - /* Intel specific adapter check for Intel integrated and Intel - * dedicated. If both exist, then change adapter priority so that the - * integrated comes first for the sake of improving overall - * performance */ - if (hasIGPU && hasDGPU) { - adapterOrder.erase(adapterOrder.begin() + iGPUIndex); - adapterOrder.insert(adapterOrder.begin(), iGPUIndex); - adapterIdx = adapterOrderadapterIdx; - } -} - void gs_device::InitAdapter(uint32_t adapterIdx) { HRESULT hr = factory->EnumAdapters1(adapterIdx, &adapter); @@ -923,7 +902,6 @@ InitCompiler(); InitFactory(); - ReorderAdapters(adapterIdx); InitAdapter(adapterIdx); InitDevice(adapterIdx); device_set_render_target(this, NULL, NULL); @@ -3068,7 +3046,7 @@ extern "C" EXPORT bool device_is_monitor_hdr(gs_device_t *device, void *monitor) { const HMONITOR hMonitor = static_cast<HMONITOR>(monitor); - return screen_supports_hdr(device, hMonitor); + return get_monitor_color_info(device, hMonitor).hdr; } extern "C" EXPORT void device_debug_marker_begin(gs_device_t *,
View file
obs-studio-28.1.2.tar.xz/libobs-d3d11/d3d11-subsystem.hpp -> obs-studio-29.0.0.tar.xz/libobs-d3d11/d3d11-subsystem.hpp
Changed
@@ -979,6 +979,16 @@ float mat16; }; +struct gs_monitor_color_info { + bool hdr; + UINT bits_per_color; + + gs_monitor_color_info(bool hdr, int bits_per_color) + : hdr(hdr), bits_per_color(bits_per_color) + { + } +}; + struct gs_device { ComPtr<IDXGIFactory1> factory; ComPtr<IDXGIAdapter1> adapter; @@ -1035,11 +1045,10 @@ vector<gs_device_loss> loss_callbacks; gs_obj *first_obj = nullptr; - vector<std::pair<HMONITOR, bool>> monitor_to_hdr; + vector<std::pair<HMONITOR, gs_monitor_color_info>> monitor_to_hdr; void InitCompiler(); void InitFactory(); - void ReorderAdapters(uint32_t &adapterIdx); void InitAdapter(uint32_t adapterIdx); void InitDevice(uint32_t adapterIdx);
View file
obs-studio-28.1.2.tar.xz/libobs-opengl/gl-cocoa.m -> obs-studio-29.0.0.tar.xz/libobs-opengl/gl-cocoa.m
Changed
@@ -342,21 +342,24 @@ struct gs_texture_2d *tex = bzalloc(sizeof(struct gs_texture_2d)); OSType pf = IOSurfaceGetPixelFormat(ref); + const bool l10r = pf == 'l10r'; if (pf == 0) blog(LOG_ERROR, "Invalid IOSurface Buffer"); - else if (pf != 'BGRA') + else if ((pf != 'BGRA') && !l10r) blog(LOG_ERROR, "Unexpected pixel format: %d (%c%c%c%c)", pf, pf >> 24, pf >> 16, pf >> 8, pf); - const enum gs_color_format color_format = GS_BGRA; + const enum gs_color_format color_format = l10r ? GS_R10G10B10A2 + : GS_BGRA; tex->base.device = device; tex->base.type = GS_TEXTURE_2D; - tex->base.format = GS_BGRA; + tex->base.format = color_format; tex->base.levels = 1; - tex->base.gl_format = convert_gs_format(color_format); + tex->base.gl_format = l10r ? GL_BGRA : convert_gs_format(color_format); tex->base.gl_internal_format = convert_gs_internal_format(color_format); - tex->base.gl_type = GL_UNSIGNED_INT_8_8_8_8_REV; + tex->base.gl_type = l10r ? GL_UNSIGNED_INT_2_10_10_10_REV + : GL_UNSIGNED_INT_8_8_8_8_REV; tex->base.gl_target = GL_TEXTURE_RECTANGLE_ARB; tex->base.is_dynamic = false; tex->base.is_render_target = false; @@ -427,11 +430,9 @@ OSType pf = IOSurfaceGetPixelFormat(ref); if (pf == 0) { blog(LOG_ERROR, "Invalid IOSurface buffer"); - } else { - if (pf != 'BGRA') - blog(LOG_ERROR, - "Unexpected pixel format: %d (%c%c%c%c)", pf, - pf >> 24, pf >> 16, pf >> 8, pf); + } else if ((pf != 'BGRA') && (pf != 'l10r')) { + blog(LOG_ERROR, "Unexpected pixel format: %d (%c%c%c%c)", pf, + pf >> 24, pf >> 16, pf >> 8, pf); } tex->width = IOSurfaceGetWidth(ref);
View file
obs-studio-28.1.2.tar.xz/libobs/CMakeLists.txt -> obs-studio-29.0.0.tar.xz/libobs/CMakeLists.txt
Changed
@@ -290,6 +290,8 @@ util/threading-windows.h util/pipe-windows.c util/platform-windows.c + util/windows/device-enum.c + util/windows/device-enum.h util/windows/obfuscate.c util/windows/obfuscate.h util/windows/win-registry.h @@ -310,7 +312,7 @@ libobs PRIVATE UNICODE _UNICODE _CRT_SECURE_NO_WARNINGS _CRT_NONSTDC_NO_WARNINGS) - target_link_libraries(libobs PRIVATE Avrt Dwmapi winmm) + target_link_libraries(libobs PRIVATE dxgi Avrt Dwmapi winmm) if(MSVC) target_link_libraries(libobs PUBLIC OBS::w32-pthreads) @@ -318,7 +320,8 @@ target_compile_options(libobs PRIVATE "$<$<COMPILE_LANGUAGE:C>:/EHc->" "$<$<COMPILE_LANGUAGE:CXX>:/EHc->") - target_link_options(libobs PRIVATE "LINKER:/SAFESEH:NO") + target_link_options(libobs PRIVATE "LINKER:/IGNORE:4098" + "LINKER:/SAFESEH:NO") endif() elseif(OS_MACOS)
View file
obs-studio-28.1.2.tar.xz/libobs/data/color.effect -> obs-studio-29.0.0.tar.xz/libobs/data/color.effect
Changed
@@ -26,6 +26,14 @@ return float3(r, g, b); } +float3 d65p3_to_rec709(float3 v) +{ + float r = dot(v, float3(1.2249401762805598, -0.22494017628055996, 0.)); + float g = dot(v, float3(-0.042056954709688163, 1.0420569547096881, 0.)); + float b = dot(v, float3(-0.019637554590334432, -0.078636045550631889, 1.0982736001409663)); + return float3(r, g, b); +} + float3 rec2020_to_rec709(float3 v) { float r = dot(v, float3(1.6604910021084345, -0.58764113878854951, -0.072849863319884883));
View file
obs-studio-28.1.2.tar.xz/libobs/data/default_rect.effect -> obs-studio-29.0.0.tar.xz/libobs/data/default_rect.effect
Changed
@@ -27,6 +27,14 @@ return image.Sample(def_sampler, vert_in.uv); } +float4 PSDrawD65P3(VertInOut vert_in) : TARGET +{ + float4 rgba = image.Sample(def_sampler, vert_in.uv); + rgba.rgb = srgb_nonlinear_to_linear(rgba.rgb); + rgba.rgb = d65p3_to_rec709(rgba.rgb); + return rgba; +} + float4 PSDrawOpaque(VertInOut vert_in) : TARGET { return float4(image.Sample(def_sampler, vert_in.uv).rgb, 1.0); @@ -48,6 +56,15 @@ } } +technique DrawD65P3 +{ + pass + { + vertex_shader = VSDefault(vert_in); + pixel_shader = PSDrawD65P3(vert_in); + } +} + technique DrawOpaque { pass
View file
obs-studio-28.1.2.tar.xz/libobs/media-io/audio-resampler-ffmpeg.c -> obs-studio-29.0.0.tar.xz/libobs/media-io/audio-resampler-ffmpeg.c
Changed
@@ -27,16 +27,20 @@ bool opened; uint32_t input_freq; - uint64_t input_layout; enum AVSampleFormat input_format; - uint8_t *output_bufferMAX_AV_PLANES; - uint64_t output_layout; enum AVSampleFormat output_format; int output_size; uint32_t output_ch; uint32_t output_freq; uint32_t output_planes; +#if LIBSWRESAMPLE_VERSION_INT < AV_VERSION_INT(4, 5, 100) + uint64_t input_layout; + uint64_t output_layout; +#else + AVChannelLayout input_ch_layout; + AVChannelLayout output_ch_layout; +#endif }; static inline enum AVSampleFormat convert_audio_format(enum audio_format format) @@ -66,6 +70,7 @@ return AV_SAMPLE_FMT_S16; } +#if LIBSWRESAMPLE_VERSION_INT < AV_VERSION_INT(4, 5, 100) static inline uint64_t convert_speaker_layout(enum speaker_layout layout) { switch (layout) { @@ -90,6 +95,7 @@ /* shouldn't get here */ return 0; } +#endif audio_resampler_t *audio_resampler_create(const struct resample_info *dst, const struct resample_info *src) @@ -99,20 +105,38 @@ rs->opened = false; rs->input_freq = src->samples_per_sec; - rs->input_layout = convert_speaker_layout(src->speakers); rs->input_format = convert_audio_format(src->format); rs->output_size = 0; rs->output_ch = get_audio_channels(dst->speakers); rs->output_freq = dst->samples_per_sec; - rs->output_layout = convert_speaker_layout(dst->speakers); rs->output_format = convert_audio_format(dst->format); rs->output_planes = is_audio_planar(dst->format) ? rs->output_ch : 1; +#if (LIBSWRESAMPLE_VERSION_INT < AV_VERSION_INT(4, 5, 100)) + rs->input_layout = convert_speaker_layout(src->speakers); + rs->output_layout = convert_speaker_layout(dst->speakers); rs->context = swr_alloc_set_opts(NULL, rs->output_layout, rs->output_format, dst->samples_per_sec, rs->input_layout, rs->input_format, src->samples_per_sec, 0, NULL); +#else + int nb_ch = get_audio_channels(src->speakers); + av_channel_layout_default(&rs->input_ch_layout, nb_ch); + av_channel_layout_default(&rs->output_ch_layout, rs->output_ch); + if (src->speakers == SPEAKERS_4POINT1) + rs->input_ch_layout = + (AVChannelLayout)AV_CHANNEL_LAYOUT_4POINT1; + + if (dst->speakers == SPEAKERS_4POINT1) + rs->output_ch_layout = + (AVChannelLayout)AV_CHANNEL_LAYOUT_4POINT1; + + swr_alloc_set_opts2(&rs->context, &rs->output_ch_layout, + rs->output_format, dst->samples_per_sec, + &rs->input_ch_layout, rs->input_format, + src->samples_per_sec, 0, NULL); +#endif if (!rs->context) { blog(LOG_ERROR, "swr_alloc_set_opts failed"); @@ -120,7 +144,13 @@ return NULL; } +#if (LIBSWRESAMPLE_VERSION_INT < AV_VERSION_INT(4, 5, 100)) if (rs->input_layout == AV_CH_LAYOUT_MONO && rs->output_ch > 1) { +#else + AVChannelLayout test_ch = AV_CHANNEL_LAYOUT_MONO; + if (av_channel_layout_compare(&rs->input_ch_layout, &test_ch) == 0 && + rs->output_ch > 1) { +#endif const double matrixMAX_AUDIO_CHANNELSMAX_AUDIO_CHANNELS = { {1}, {1, 1},
View file
obs-studio-28.1.2.tar.xz/libobs/media-io/media-remux.c -> obs-studio-29.0.0.tar.xz/libobs/media-io/media-remux.c
Changed
@@ -149,7 +149,16 @@ av_dict_copy(&out_stream->metadata, in_stream->metadata, 0); #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 48, 101) - out_stream->codecpar->codec_tag = 0; + if (in_stream->codecpar->codec_tag != 0) { + out_stream->codecpar->codec_tag = + in_stream->codecpar->codec_tag; + } else if (in_stream->codecpar->codec_id == AV_CODEC_ID_HEVC) { + // Tag HEVC files with industry standard HVC1 tag for wider device compatibility + out_stream->codecpar->codec_tag = + MKTAG('h', 'v', 'c', '1'); + } else { + out_stream->codecpar->codec_tag = 0; + } #else out_stream->codec->codec_tag = 0; out_stream->time_base = out_stream->codec->time_base;
View file
obs-studio-28.1.2.tar.xz/libobs/obs-cocoa.m -> obs-studio-29.0.0.tar.xz/libobs/obs-cocoa.m
Changed
@@ -123,6 +123,12 @@ os_get_physical_cores(), os_get_logical_cores()); } +static void log_emulation_status(void) +{ + blog(LOG_INFO, "Rosetta translation used: %s", + os_get_emulation_status() ? "true" : "false"); +} + static void log_available_memory(void) { size_t size; @@ -162,6 +168,7 @@ log_processor_cores(); log_available_memory(); log_os(); + log_emulation_status(); log_kernel_version(); }
View file
obs-studio-28.1.2.tar.xz/libobs/obs-config.h -> obs-studio-29.0.0.tar.xz/libobs/obs-config.h
Changed
@@ -27,21 +27,21 @@ /* * Increment if major breaking API changes */ -#define LIBOBS_API_MAJOR_VER 28 +#define LIBOBS_API_MAJOR_VER 29 /* * Increment if backward-compatible additions * * Reset to zero each major version */ -#define LIBOBS_API_MINOR_VER 1 +#define LIBOBS_API_MINOR_VER 0 /* * 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)
View file
obs-studio-28.1.2.tar.xz/libobs/obs-encoder.c -> obs-studio-29.0.0.tar.xz/libobs/obs-encoder.c
Changed
@@ -187,7 +187,9 @@ static inline bool gpu_encode_available(const struct obs_encoder *encoder) { - struct obs_core_video_mix *video = obs->video.main_mix; + struct obs_core_video_mix *video = get_mix_for_video(encoder->media); + if (!video) + return false; return (encoder->info.caps & OBS_ENCODER_CAP_PASS_TEXTURE) != 0 && (video->using_p010_tex || video->using_nv12_tex); }
View file
obs-studio-28.1.2.tar.xz/libobs/obs-internal.h -> obs-studio-29.0.0.tar.xz/libobs/obs-internal.h
Changed
@@ -284,6 +284,7 @@ volatile bool gpu_encode_stop; video_t *video; + struct obs_video_info ovi; bool gpu_conversion; const char *conversion_techsNUM_CHANNELS; @@ -292,7 +293,6 @@ float conversion_height_i; float color_matrix16; - enum obs_scale_type scale_type; }; extern struct obs_core_video_mix * @@ -324,9 +324,6 @@ uint32_t lagged_frames; bool thread_initialized; - uint32_t base_width; - uint32_t base_height; - gs_texture_t *transparent_texture; gs_effect_t *deinterlace_discard_effect; @@ -338,7 +335,6 @@ gs_effect_t *deinterlace_yadif_effect; gs_effect_t *deinterlace_yadif_2x_effect; - struct obs_video_info ovi; float sdr_white_level; float hdr_nominal_peak_level; @@ -365,8 +361,6 @@ int max_buffering_ticks; bool fixed_buffer; - float user_volume; - pthread_mutex_t monitoring_mutex; DARRAY(struct audio_monitor *) monitors; char *monitoring_device_name; @@ -498,6 +492,8 @@ uint64_t end_ts_in, uint64_t *out_ts, uint32_t mixers, struct audio_output_data *mixes); +extern struct obs_core_video_mix *get_mix_for_video(video_t *video); + extern void start_raw_video(video_t *video, const struct video_scale_info *conversion, void (*callback)(void *param, struct video_data *frame),
View file
obs-studio-28.1.2.tar.xz/libobs/obs-nix-wayland.c -> obs-studio-29.0.0.tar.xz/libobs/obs-nix-wayland.c
Changed
@@ -1061,6 +1061,21 @@ return OBS_KEY_NUM8; case XKB_KEY_KP_9: return OBS_KEY_NUM9; + + case XKB_KEY_XF86AudioPlay: + return OBS_KEY_VK_MEDIA_PLAY_PAUSE; + case XKB_KEY_XF86AudioStop: + return OBS_KEY_VK_MEDIA_STOP; + case XKB_KEY_XF86AudioPrev: + return OBS_KEY_VK_MEDIA_PREV_TRACK; + case XKB_KEY_XF86AudioNext: + return OBS_KEY_VK_MEDIA_NEXT_TRACK; + case XKB_KEY_XF86AudioMute: + return OBS_KEY_VK_VOLUME_MUTE; + case XKB_KEY_XF86AudioRaiseVolume: + return OBS_KEY_VK_VOLUME_DOWN; + case XKB_KEY_XF86AudioLowerVolume: + return OBS_KEY_VK_VOLUME_UP; } return OBS_KEY_NONE; } @@ -1607,6 +1622,21 @@ return XKB_KEY_KP_8; case OBS_KEY_NUM9: return XKB_KEY_KP_9; + + case OBS_KEY_VK_MEDIA_PLAY_PAUSE: + return XKB_KEY_XF86AudioPlay; + case OBS_KEY_VK_MEDIA_STOP: + return XKB_KEY_XF86AudioStop; + case OBS_KEY_VK_MEDIA_PREV_TRACK: + return XKB_KEY_XF86AudioPrev; + case OBS_KEY_VK_MEDIA_NEXT_TRACK: + return XKB_KEY_XF86AudioNext; + case OBS_KEY_VK_VOLUME_MUTE: + return XKB_KEY_XF86AudioMute; + case OBS_KEY_VK_VOLUME_DOWN: + return XKB_KEY_XF86AudioRaiseVolume; + case OBS_KEY_VK_VOLUME_UP: + return XKB_KEY_XF86AudioLowerVolume; default: break; }
View file
obs-studio-28.1.2.tar.xz/libobs/obs-nix-x11.c -> obs-studio-29.0.0.tar.xz/libobs/obs-nix-x11.c
Changed
@@ -673,6 +673,21 @@ case OBS_KEY_MOUSE5: return MOUSE_5; + case OBS_KEY_VK_MEDIA_PLAY_PAUSE: + return XF86XK_AudioPlay; + case OBS_KEY_VK_MEDIA_STOP: + return XF86XK_AudioStop; + case OBS_KEY_VK_MEDIA_PREV_TRACK: + return XF86XK_AudioPrev; + case OBS_KEY_VK_MEDIA_NEXT_TRACK: + return XF86XK_AudioNext; + case OBS_KEY_VK_VOLUME_MUTE: + return XF86XK_AudioMute; + case OBS_KEY_VK_VOLUME_DOWN: + return XF86XK_AudioRaiseVolume; + case OBS_KEY_VK_VOLUME_UP: + return XF86XK_AudioLowerVolume; + /* TODO: Implement keys for non-US keyboards */ default:; }
View file
obs-studio-28.1.2.tar.xz/libobs/obs-properties.c -> obs-studio-29.0.0.tar.xz/libobs/obs-properties.c
Changed
@@ -169,6 +169,12 @@ bfree(data->suffix); } +static inline void button_data_free(struct button_data *data) +{ + if (data->url) + bfree(data->url); +} + struct obs_properties; struct obs_property { @@ -259,6 +265,8 @@ int_data_free(get_property_data(property)); else if (property->type == OBS_PROPERTY_FLOAT) float_data_free(get_property_data(property)); + else if (property->type == OBS_PROPERTY_BUTTON) + button_data_free(get_property_data(property)); bfree(property->name); bfree(property->desc); @@ -1154,7 +1162,7 @@ if (!data) return; - data->url = url; + data->url = bstrdup(url); } void obs_property_list_clear(obs_property_t *p)
View file
obs-studio-28.1.2.tar.xz/libobs/obs-scene.c -> obs-studio-29.0.0.tar.xz/libobs/obs-scene.c
Changed
@@ -1265,13 +1265,21 @@ static uint32_t scene_getwidth(void *data) { obs_scene_t *scene = data; - return scene->custom_size ? scene->cx : obs->video.base_width; + if (scene->custom_size) + return scene->cx; + if (obs->video.main_mix) + return obs->video.main_mix->ovi.base_width; + return 0; } static uint32_t scene_getheight(void *data) { obs_scene_t *scene = data; - return scene->custom_size ? scene->cy : obs->video.base_height; + if (scene->custom_size) + return scene->cy; + if (obs->video.main_mix) + return obs->video.main_mix->ovi.base_height; + return 0; } static void apply_scene_item_audio_actions(struct obs_scene_item *item,
View file
obs-studio-28.1.2.tar.xz/libobs/obs-source-deinterlace.c -> obs-studio-29.0.0.tar.xz/libobs/obs-source-deinterlace.c
Changed
@@ -250,40 +250,24 @@ } } -static inline struct obs_source_frame *get_prev_frame(obs_source_t *source, - bool *updated) +void deinterlace_update_async_video(obs_source_t *source) { - struct obs_source_frame *frame = NULL; + if (source->deinterlace_rendered) + return; + + source->deinterlace_rendered = true; pthread_mutex_lock(&source->async_mutex); - *updated = source->cur_async_frame != NULL; - frame = source->prev_async_frame; + const bool updated = source->cur_async_frame != NULL; + struct obs_source_frame *frame = source->prev_async_frame; source->prev_async_frame = NULL; - if (frame) - os_atomic_inc_long(&frame->refs); - pthread_mutex_unlock(&source->async_mutex); - return frame; -} - -void deinterlace_update_async_video(obs_source_t *source) -{ - struct obs_source_frame *frame; - bool updated; - - if (source->deinterlace_rendered) - return; - - frame = get_prev_frame(source, &updated); - - source->deinterlace_rendered = true; - if (frame) - frame = filter_async_video(source, frame); - if (frame) { + os_atomic_inc_long(&frame->refs); + if (set_async_texture_size(source, frame)) { update_async_textures(source, frame, source->async_prev_textures,
View file
obs-studio-28.1.2.tar.xz/libobs/obs-source.c -> obs-studio-29.0.0.tar.xz/libobs/obs-source.c
Changed
@@ -77,6 +77,7 @@ static const char *source_signals = { "void destroy(ptr source)", "void remove(ptr source)", + "void update(ptr source)", "void save(ptr source)", "void load(ptr source)", "void activate(ptr source)", @@ -203,7 +204,7 @@ return false; if (pthread_mutex_init(&source->audio_mutex, NULL) != 0) return false; - if (pthread_mutex_init(&source->async_mutex, NULL) != 0) + if (pthread_mutex_init_recursive(&source->async_mutex) != 0) return false; if (pthread_mutex_init(&source->caption_cb_mutex, NULL) != 0) return false; @@ -968,6 +969,7 @@ source->context.settings); os_atomic_compare_swap_long(&source->defer_update_count, count, 0); + obs_source_dosignal(source, "source_update", "update"); } } @@ -985,6 +987,7 @@ } else if (source->context.data && source->info.update) { source->info.update(source->context.data, source->context.settings); + obs_source_dosignal(source, "source_update", "update"); } } @@ -1184,8 +1187,20 @@ static inline struct obs_source_frame *get_closest_frame(obs_source_t *source, uint64_t sys_time); -bool set_async_texture_size(struct obs_source *source, - const struct obs_source_frame *frame); + +static void filter_frame(obs_source_t *source, + struct obs_source_frame **ref_frame) +{ + struct obs_source_frame *frame = *ref_frame; + if (frame) { + os_atomic_inc_long(&frame->refs); + frame = filter_async_video(source, frame); + if (frame) + os_atomic_dec_long(&frame->refs); + } + + *ref_frame = frame; +} static void async_tick(obs_source_t *source) { @@ -1205,6 +1220,11 @@ } source->last_sys_timestamp = sys_time; + + if (deinterlacing_enabled(source)) + filter_frame(source, &source->prev_async_frame); + filter_frame(source, &source->cur_async_frame); + pthread_mutex_unlock(&source->async_mutex); if (source->cur_async_frame) @@ -2396,12 +2416,9 @@ static void obs_source_update_async_video(obs_source_t *source) { if (!source->async_rendered) { - struct obs_source_frame *frame = obs_source_get_frame(source); - - if (frame) - frame = filter_async_video(source, frame); - source->async_rendered = true; + + struct obs_source_frame *frame = obs_source_get_frame(source); if (frame) { check_to_swap_bgrx_bgra(source, frame); @@ -2475,6 +2492,7 @@ nonlinear_alpha ? "DrawNonlinearAlphaMultiply" : "DrawMultiply"; + linear_srgb = true; multiplier = obs_get_video_sdr_white_level() / 80.0f; }
View file
obs-studio-28.1.2.tar.xz/libobs/obs-video.c -> obs-studio-29.0.0.tar.xz/libobs/obs-video.c
Changed
@@ -125,8 +125,8 @@ static const char *render_main_texture_name = "render_main_texture"; static inline void render_main_texture(struct obs_core_video_mix *video) { - uint32_t base_width = obs->video.base_width; - uint32_t base_height = obs->video.base_height; + uint32_t base_width = video->ovi.base_width; + uint32_t base_height = video->ovi.base_height; profile_start(render_main_texture_name); GS_DEBUG_MARKER_BEGIN(GS_DEBUG_COLOR_MAIN_TEXTURE, @@ -170,12 +170,12 @@ /* if the dimension is under half the size of the original image, * bicubic/lanczos can't sample enough pixels to create an accurate * image, so use the bilinear low resolution effect instead */ - if (info->width < (video->base_width / 2) && - info->height < (video->base_height / 2)) { + if (info->width < (mix->ovi.base_width / 2) && + info->height < (mix->ovi.base_height / 2)) { return video->bilinear_lowres_effect; } - switch (mix->scale_type) { + switch (mix->ovi.scale_type) { case OBS_SCALE_BILINEAR: return video->default_effect; case OBS_SCALE_LANCZOS: @@ -189,11 +189,11 @@ return video->bicubic_effect; } -static inline bool resolution_close(struct obs_core_video *video, +static inline bool resolution_close(struct obs_core_video_mix *mix, uint32_t width, uint32_t height) { - long width_cmp = (long)video->base_width - (long)width; - long height_cmp = (long)video->base_height - (long)height; + long width_cmp = (long)mix->ovi.base_width - (long)width; + long height_cmp = (long)mix->ovi.base_height - (long)height; return labs(width_cmp) <= 16 && labs(height_cmp) <= 16; } @@ -203,7 +203,7 @@ { struct obs_core_video *video = &obs->video; - if (resolution_close(video, width, height)) { + if (resolution_close(mix, width, height)) { return video->default_effect; } else { /* if the scale method couldn't be loaded, use either bicubic @@ -233,8 +233,8 @@ if (video_output_get_format(mix->video) == VIDEO_FORMAT_BGRA) { tech = gs_effect_get_technique(effect, "DrawAlphaDivide"); } else { - if ((width == video->base_width) && - (height == video->base_height)) + if ((width == mix->ovi.base_width) && + (height == mix->ovi.base_height)) return texture; tech = gs_effect_get_technique(effect, "Draw"); @@ -254,15 +254,15 @@ if (bres) { struct vec2 base; - vec2_set(&base, (float)video->base_width, - (float)video->base_height); + vec2_set(&base, (float)mix->ovi.base_width, + (float)mix->ovi.base_height); gs_effect_set_vec2(bres, &base); } if (bres_i) { struct vec2 base_i; - vec2_set(&base_i, 1.0f / (float)video->base_width, - 1.0f / (float)video->base_height); + vec2_set(&base_i, 1.0f / (float)mix->ovi.base_width, + 1.0f / (float)mix->ovi.base_height); gs_effect_set_vec2(bres_i, &base_i); }
View file
obs-studio-28.1.2.tar.xz/libobs/obs-view.c -> obs-studio-29.0.0.tar.xz/libobs/obs-view.c
Changed
@@ -162,10 +162,17 @@ video_t *obs_view_add(obs_view_t *view) { - if (!view) + if (!obs->video.main_mix) + return NULL; + return obs_view_add2(view, &obs->video.main_mix->ovi); +} + +video_t *obs_view_add2(obs_view_t *view, struct obs_video_info *ovi) +{ + if (!view || !ovi) return NULL; - struct obs_core_video_mix *mix = obs_create_video_mix(&obs->video.ovi); + struct obs_core_video_mix *mix = obs_create_video_mix(ovi); if (!mix) { return NULL; }
View file
obs-studio-28.1.2.tar.xz/libobs/obs-windows.c -> obs-studio-29.0.0.tar.xz/libobs/obs-windows.c
Changed
@@ -108,6 +108,13 @@ os_get_physical_cores(), os_get_logical_cores()); } +static void log_emulation_status(void) +{ + if (os_get_emulation_status()) { + blog(LOG_WARNING, "Windows ARM64: Running with x64 emulation"); + } +} + static void log_available_memory(void) { MEMORYSTATUSEX ms; @@ -138,10 +145,13 @@ bool b64 = is_64_bit_windows(); const char *windows_bitness = b64 ? "64" : "32"; + bool arm64 = is_arm64_windows(); + const char *arm64_windows = arm64 ? "ARM " : ""; + blog(LOG_INFO, - "Windows Version: %d.%d Build %d (release: %s; revision: %d; %s-bit)", + "Windows Version: %d.%d Build %d (release: %s; revision: %d; %s%s-bit)", ver.major, ver.minor, ver.build, release_id, ver.revis, - windows_bitness); + arm64_windows, windows_bitness); } static void log_admin_status(void) @@ -164,36 +174,6 @@ success ? "true" : "false"); } -typedef HRESULT(WINAPI *dwm_is_composition_enabled_t)(BOOL *); - -static void log_aero(void) -{ - dwm_is_composition_enabled_t composition_enabled = NULL; - - const char *aeroMessage = - win_ver >= 0x602 - ? " (Aero is always on for windows 8 and above)" - : ""; - - HMODULE dwm = LoadLibraryW(L"dwmapi"); - BOOL bComposition = true; - - if (!dwm) { - return; - } - - composition_enabled = (dwm_is_composition_enabled_t)GetProcAddress( - dwm, "DwmIsCompositionEnabled"); - if (!composition_enabled) { - FreeLibrary(dwm); - return; - } - - composition_enabled(&bComposition); - blog(LOG_INFO, "Aero is %s%s", bComposition ? "Enabled" : "Disabled", - aeroMessage); -} - #define WIN10_GAME_BAR_REG_KEY \ L"Software\\Microsoft\\Windows\\CurrentVersion\\GameDVR" #define WIN10_GAME_DVR_POLICY_REG_KEY \ @@ -407,8 +387,8 @@ log_processor_cores(); log_available_memory(); log_windows_version(); + log_emulation_status(); log_admin_status(); - log_aero(); log_gaming_features(); log_security_products(); }
View file
obs-studio-28.1.2.tar.xz/libobs/obs.c -> obs-studio-29.0.0.tar.xz/libobs/obs.c
Changed
@@ -398,7 +398,7 @@ } video->render_texture = - gs_texture_create(obs->video.base_width, obs->video.base_height, + gs_texture_create(video->ovi.base_width, video->ovi.base_height, format, 1, NULL, GS_RENDER_TARGET); if (!video->render_texture) success = false; @@ -586,8 +586,20 @@ pthread_mutex_init_value(&video->gpu_encoder_mutex); make_video_info(&vi, ovi); + video->ovi = *ovi; + + /* main view graphics thread drives all frame output, + * so share FPS settings for aux views */ + pthread_mutex_lock(&obs->video.mixes_mutex); + size_t num = obs->video.mixes.num; + if (num && obs->video.main_mix) { + struct obs_video_info main_ovi = obs->video.main_mix->ovi; + video->ovi.fps_num = main_ovi.fps_num; + video->ovi.fps_den = main_ovi.fps_den; + } + pthread_mutex_unlock(&obs->video.mixes_mutex); + video->gpu_conversion = ovi->gpu_conversion; - video->scale_type = ovi->scale_type; video->gpu_was_active = false; video->raw_was_active = false; video->was_active = false; @@ -634,8 +646,6 @@ static int obs_init_video(struct obs_video_info *ovi) { struct obs_core_video *video = &obs->video; - video->base_width = ovi->base_width; - video->base_height = ovi->base_height; video->video_frame_interval_ns = util_mul_div64(1000000000ULL, ovi->fps_den, ovi->fps_num); video->video_half_frame_interval_ns = @@ -646,9 +656,7 @@ if (pthread_mutex_init(&video->mixes_mutex, NULL) < 0) return OBS_VIDEO_FAIL; - video->ovi = *ovi; - - if (!obs_view_add(&obs->data.main_view)) + if (!obs_view_add2(&obs->data.main_view, ovi)) return OBS_VIDEO_FAIL; int errorcode; @@ -831,8 +839,6 @@ struct obs_task_info audio_init = {.task = set_audio_thread}; circlebuf_push_back(&audio->tasks, &audio_init, sizeof(audio_init)); - audio->user_volume = 1.0f; - audio->monitoring_device_name = bstrdup("Default"); audio->monitoring_device_id = bstrdup("default"); @@ -970,6 +976,7 @@ "void source_create(ptr source)", "void source_destroy(ptr source)", "void source_remove(ptr source)", + "void source_update(ptr source)", "void source_save(ptr source)", "void source_load(ptr source)", "void source_activate(ptr source)", @@ -987,7 +994,6 @@ "void source_transition_stop(ptr source)", "void channel_change(int channel, in out ptr source, ptr prev_source)", - "void master_volume(in out float volume)", "void hotkey_layout_change()", "void hotkey_register(ptr hotkey)", @@ -1509,10 +1515,10 @@ bool obs_get_video_info(struct obs_video_info *ovi) { - if (!obs->video.graphics) + if (!obs->video.graphics || !obs->video.main_mix) return false; - *ovi = obs->video.ovi; + *ovi = obs->video.main_mix->ovi; return true; } @@ -2090,19 +2096,12 @@ void obs_set_master_volume(float volume) { - struct calldata data = {0}; - - calldata_set_float(&data, "volume", volume); - signal_handler_signal(obs->signals, "master_volume", &data); - volume = (float)calldata_float(&data, "volume"); - calldata_free(&data); - - obs->audio.user_volume = volume; + UNUSED_PARAMETER(volume); } float obs_get_master_volume(void) { - return obs->audio.user_volume; + return 1.f; } static obs_source_t *obs_load_source_type(obs_data_t *source_data, @@ -2824,7 +2823,7 @@ bool start_gpu_encode(obs_encoder_t *encoder) { - struct obs_core_video_mix *video = obs->video.main_mix; + struct obs_core_video_mix *video = get_mix_for_video(encoder->media); bool success = true; obs_enter_graphics(); @@ -2850,7 +2849,7 @@ void stop_gpu_encode(obs_encoder_t *encoder) { - struct obs_core_video_mix *video = obs->video.main_mix; + struct obs_core_video_mix *video = get_mix_for_video(encoder->media); bool call_free = false; os_atomic_dec_long(&video->gpu_encoder_active);
View file
obs-studio-28.1.2.tar.xz/libobs/obs.h -> obs-studio-29.0.0.tar.xz/libobs/obs.h
Changed
@@ -754,10 +754,10 @@ EXPORT gs_texture_t *obs_get_main_texture(void); /** Sets the master user volume */ -EXPORT void obs_set_master_volume(float volume); +OBS_DEPRECATED EXPORT void obs_set_master_volume(float volume); /** Gets the master user volume */ -EXPORT float obs_get_master_volume(void); +OBS_DEPRECATED EXPORT float obs_get_master_volume(void); /** Saves a source to settings data */ EXPORT obs_data_t *obs_save_source(obs_source_t *source); @@ -909,9 +909,12 @@ /** Renders the sources of this view context */ EXPORT void obs_view_render(obs_view_t *view); -/** Adds a view to the main render loop */ +/** Adds a view to the main render loop, with current obs_get_video_info state */ EXPORT video_t *obs_view_add(obs_view_t *view); +/** Adds a view to the main render loop, with custom video settings */ +EXPORT video_t *obs_view_add2(obs_view_t *view, struct obs_video_info *ovi); + /** Removes a view from the main render loop */ EXPORT void obs_view_remove(obs_view_t *view);
View file
obs-studio-28.1.2.tar.xz/libobs/obsconfig.h.in -> obs-studio-29.0.0.tar.xz/libobs/obsconfig.h.in
Changed
@@ -16,6 +16,7 @@ #define OBS_PLUGIN_DESTINATION "@OBS_PLUGIN_DESTINATION@" #define OBS_QT_VERSION @_QT_VERSION@ +#cmakedefine OBS_COMMIT "@OBS_COMMIT@" #cmakedefine LINUX_PORTABLE #cmakedefine GIO_FOUND #cmakedefine PULSEAUDIO_FOUND
View file
obs-studio-28.1.2.tar.xz/libobs/util/platform-cocoa.m -> obs-studio-29.0.0.tar.xz/libobs/util/platform-cocoa.m
Changed
@@ -386,6 +386,28 @@ return vmstat.free_count * vm_page_size; } +static uint64_t total_memory = 0; +static bool total_memory_initialized = false; + +static void os_get_sys_total_size_internal() +{ + total_memory_initialized = true; + + size_t size; + int ret; + + size = sizeof(total_memory); + ret = sysctlbyname("hw.memsize", &total_memory, &size, NULL, 0); +} + +uint64_t os_get_sys_total_size(void) +{ + if (!total_memory_initialized) + os_get_sys_total_size_internal(); + + return total_memory; +} + #ifndef MACH_TASK_BASIC_INFO typedef task_basic_info_data_t mach_task_basic_info_data_t; #endif
View file
obs-studio-28.1.2.tar.xz/libobs/util/platform-nix.c -> obs-studio-29.0.0.tar.xz/libobs/util/platform-nix.c
Changed
@@ -53,6 +53,9 @@ #else #include <sys/resource.h> #endif +#if !defined(__OpenBSD__) +#include <sys/sysinfo.h> +#endif #include <spawn.h> #endif @@ -1100,6 +1103,30 @@ return (uint64_t)statm.virtual_size; } #endif + +static uint64_t total_memory = 0; +static bool total_memory_initialized = false; + +static void os_get_sys_total_size_internal() +{ + total_memory_initialized = true; + +#ifndef __OpenBSD__ + struct sysinfo info; + if (sysinfo(&info) < 0) + return; + + total_memory = (uint64_t)info.totalram * info.mem_unit; +#endif +} + +uint64_t os_get_sys_total_size(void) +{ + if (!total_memory_initialized) + os_get_sys_total_size_internal(); + + return total_memory; +} #endif uint64_t os_get_free_disk_space(const char *dir)
View file
obs-studio-28.1.2.tar.xz/libobs/util/platform-windows.c -> obs-studio-29.0.0.tar.xz/libobs/util/platform-windows.c
Changed
@@ -1088,9 +1088,26 @@ #endif } +bool is_arm64_windows(void) +{ +#if defined(_M_ARM64) || defined(_M_ARM64EC) + return true; +#else + USHORT processMachine; + USHORT nativeMachine; + bool result = IsWow64Process2(GetCurrentProcess(), &processMachine, + &nativeMachine); + return (result && (nativeMachine == IMAGE_FILE_MACHINE_ARM64)); +#endif +} + bool os_get_emulation_status(void) { +#if defined(_M_ARM64) || defined(_M_ARM64EC) return false; +#else + return is_arm64_windows(); +#endif } void get_reg_dword(HKEY hkey, LPCWSTR sub_key, LPCWSTR value_name, @@ -1187,7 +1204,9 @@ ver->build = wcstol(str, NULL, 10); } - if (get_reg_sz(key, L"ReleaseId", str, sizeof(str))) { + const wchar_t *release_key = ver->build > 19041 ? L"DisplayVersion" + : L"ReleaseId"; + if (get_reg_sz(key, release_key, str, sizeof(str))) { os_wcs_to_utf8(str, 0, win_release_id, MAX_SZ_LEN); } @@ -1390,6 +1409,28 @@ return msex.ullAvailPhys; } +static uint64_t total_memory = 0; +static bool total_memory_initialized = false; + +static void os_get_sys_total_size_internal() +{ + total_memory_initialized = true; + + MEMORYSTATUSEX msex = {sizeof(MEMORYSTATUSEX)}; + if (!os_get_sys_memory_usage_internal(&msex)) + return; + + total_memory = msex.ullTotalPhys; +} + +uint64_t os_get_sys_total_size(void) +{ + if (!total_memory_initialized) + os_get_sys_total_size_internal(); + + return total_memory; +} + static inline bool os_get_proc_memory_usage_internal(PROCESS_MEMORY_COUNTERS *pmc) {
View file
obs-studio-28.1.2.tar.xz/libobs/util/platform.c -> obs-studio-29.0.0.tar.xz/libobs/util/platform.c
Changed
@@ -559,7 +559,8 @@ double os_strtod(const char *str) { char buf64; - snprintf(buf, 64, "%s", str); + strncpy(buf, str, sizeof(buf) - 1); + bufsizeof(buf) - 1 = 0; to_locale(buf); return strtod(buf, NULL); } @@ -760,23 +761,25 @@ if (!convert0) { if (astrcmp_n(cmp, "%FPS", 4) == 0) { if (ovi.fps_den <= 1) { - sprintf(convert, "%u", ovi.fps_num); + snprintf(convert, sizeof(convert), "%u", + ovi.fps_num); } else { const double obsFPS = (double)ovi.fps_num / (double)ovi.fps_den; - sprintf(convert, "%.2f", obsFPS); + snprintf(convert, sizeof(convert), + "%.2f", obsFPS); } replace_text(&sf, pos, 4, convert); } else if (astrcmp_n(cmp, "%CRES", 5) == 0) { - sprintf(convert, "%ux%u", ovi.base_width, - ovi.base_height); + snprintf(convert, sizeof(convert), "%ux%u", + ovi.base_width, ovi.base_height); replace_text(&sf, pos, 5, convert); } else if (astrcmp_n(cmp, "%ORES", 5) == 0) { - sprintf(convert, "%ux%u", ovi.output_width, - ovi.output_height); + snprintf(convert, sizeof(convert), "%ux%u", + ovi.output_width, ovi.output_height); replace_text(&sf, pos, 5, convert); } else if (astrcmp_n(cmp, "%VF", 3) == 0) { @@ -785,7 +788,8 @@ replace_text(&sf, pos, 3, convert); } else if (astrcmp_n(cmp, "%s", 2) == 0) { - sprintf(convert, "%" PRId64, (int64_t)now); + snprintf(convert, sizeof(convert), "%" PRId64, + (int64_t)now); replace_text(&sf, pos, 2, convert); } }
View file
obs-studio-28.1.2.tar.xz/libobs/util/platform.h -> obs-studio-29.0.0.tar.xz/libobs/util/platform.h
Changed
@@ -189,6 +189,7 @@ EXPORT int os_get_logical_cores(void); EXPORT uint64_t os_get_sys_free_size(void); +EXPORT uint64_t os_get_sys_total_size(void); struct os_proc_memory_usage { uint64_t resident_size;
View file
obs-studio-29.0.0.tar.xz/libobs/util/windows/device-enum.c
Added
@@ -0,0 +1,32 @@ +#include "device-enum.h" +#include "../dstr.h" + +#include <dxgi.h> + +void enum_graphics_device_luids(device_luid_cb device_luid, void *param) +{ + IDXGIFactory1 *factory; + IDXGIAdapter1 *adapter; + HRESULT hr; + + hr = CreateDXGIFactory1(&IID_IDXGIFactory1, (void **)&factory); + if (FAILED(hr)) + return; + + for (UINT i = 0; + factory->lpVtbl->EnumAdapters1(factory, i, &adapter) == S_OK; + i++) { + DXGI_ADAPTER_DESC desc; + + hr = adapter->lpVtbl->GetDesc(adapter, &desc); + adapter->lpVtbl->Release(adapter); + if (FAILED(hr)) + continue; + + uint64_t luid64 = *(uint64_t *)&desc.AdapterLuid; + if (!device_luid(param, i, luid64)) + break; + } + + factory->lpVtbl->Release(factory); +}
View file
obs-studio-29.0.0.tar.xz/libobs/util/windows/device-enum.h
Added
@@ -0,0 +1,14 @@ +#pragma once + +#include "../c99defs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef bool (*device_luid_cb)(void *param, uint32_t idx, uint64_t luid); +EXPORT void enum_graphics_device_luids(device_luid_cb device_luid, void *param); + +#ifdef __cplusplus +} +#endif
View file
obs-studio-28.1.2.tar.xz/libobs/util/windows/win-version.h -> obs-studio-29.0.0.tar.xz/libobs/util/windows/win-version.h
Changed
@@ -48,6 +48,7 @@ } EXPORT bool is_64_bit_windows(void); +EXPORT bool is_arm64_windows(void); EXPORT bool get_dll_ver(const wchar_t *lib, struct win_version_info *info); EXPORT void get_win_ver(struct win_version_info *info); EXPORT uint32_t get_win_ver_int(void);
View file
obs-studio-28.1.2.tar.xz/plugins/aja/aja-presets.cpp -> obs-studio-29.0.0.tar.xz/plugins/aja/aja-presets.cpp
Changed
@@ -187,6 +187,27 @@ {DEVICE_ID_IO4KPLUS}, false, false}}, + {"HDMI_UHD_4K_YCbCr_Capture", + {"HDMI_UHD_4K_YCbCr_Capture", + ConnectionKind::HDMI, + NTV2_MODE_CAPTURE, + RasterDefinition::UHD_4K, + HDMIWireFormat::UHD_4K_YCBCR, + VPIDStandard_Unknown, + 1, + 2, + kEnable4KTSI, + "hdmi{ch1}0->tsi{ch1}0;" + "hdmi{ch1}1->tsi{ch1}1;" + "hdmi{ch1}2->tsi{ch2}0;" + "hdmi{ch1}3->tsi{ch2}1;" + "tsi{ch1}0->fb{ch1}0;" + "tsi{ch1}1->fb{ch1}1;" + "tsi{ch2}0->fb{ch2}0;" + "tsi{ch2}1->fb{ch2}1;", + {}, + false, + false}}, /* * HDMI YCbCr Display */
View file
obs-studio-28.1.2.tar.xz/plugins/aja/aja-props.cpp -> obs-studio-29.0.0.tar.xz/plugins/aja/aja-props.cpp
Changed
@@ -155,7 +155,7 @@ NTV2_IS_4K_VIDEO_FORMAT(videoFormat)) { return NTV2_CHANNEL3; } - return NTV2InputSourceToChannel(InitialInputSource()); + return Channel(); } NTV2AudioSystem SourceProps::AudioSystem() const
View file
obs-studio-28.1.2.tar.xz/plugins/aja/aja-source.cpp -> obs-studio-29.0.0.tar.xz/plugins/aja/aja-source.cpp
Changed
@@ -269,6 +269,7 @@ sourceProps.pixelFormat); auto inputSource = sourceProps.InitialInputSource(); auto channel = sourceProps.Channel(); + auto framestore = sourceProps.Framestore(); auto audioSystem = sourceProps.AudioSystem(); // Current "on-air" frame on the card. The capture thread "Ping-pongs" between // two frames, starting at an index corresponding to the framestore channel. @@ -278,12 +279,12 @@ // Channel 3 (index 2) = frames 4/5 // Channel 4 (index 3) = frames 6/7 // etc... - ULWord currentCardFrame = (uint32_t)channel * 2; + ULWord currentCardFrame = GetIndexForNTV2Channel(framestore) * 2; card->WaitForInputFieldID(NTV2_FIELD0, channel); currentCardFrame ^= 1; - card->SetInputFrame(channel, currentCardFrame); + card->SetInputFrame(framestore, currentCardFrame); AudioOffsets offsets; ResetAudioBufferOffsets(card, audioSystem, offsets); @@ -388,7 +389,7 @@ obs_source_output_video2(ajaSource->mSource, &obsFrame); - card->SetInputFrame(channel, currentCardFrame); + card->SetInputFrame(framestore, currentCardFrame); } blog(LOG_INFO, "AJASource::Capturethread: Thread loop stopped");
View file
obs-studio-28.1.2.tar.xz/plugins/coreaudio-encoder/encoder.cpp -> obs-studio-29.0.0.tar.xz/plugins/coreaudio-encoder/encoder.cpp
Changed
@@ -175,7 +175,7 @@ char array4096; va_start(args, fmt); - vsnprintf(array, 4096, fmt, args); + vsnprintf(array, sizeof(array), fmt, args); va_end(args); array4095 = 0;
View file
obs-studio-28.1.2.tar.xz/plugins/decklink/decklink-device-instance.cpp -> obs-studio-29.0.0.tar.xz/plugins/decklink/decklink-device-instance.cpp
Changed
@@ -521,10 +521,9 @@ mode = mode_; - int keyerMode = device->GetKeyerMode(); - ComPtr<IDeckLinkKeyer> deckLinkKeyer; if (device->GetKeyer(&deckLinkKeyer)) { + const int keyerMode = device->GetKeyerMode(); if (keyerMode) { deckLinkKeyer->Enable(keyerMode == 1); deckLinkKeyer->SetLevel(255); @@ -537,21 +536,11 @@ if (decklinkOutput == nullptr) return false; - int rowBytes = decklinkOutput->GetWidth() * 2; - if (decklinkOutput->keyerMode != 0) { - rowBytes = decklinkOutput->GetWidth() * 4; - } - - BMDPixelFormat pixelFormat = bmdFormat8BitYUV; - if (keyerMode != 0) { - pixelFormat = bmdFormat8BitBGRA; - } - HRESULT result; - result = output->CreateVideoFrame(decklinkOutput->GetWidth(), - decklinkOutput->GetHeight(), rowBytes, - pixelFormat, bmdFrameFlagDefault, - &decklinkOutputFrame); + result = output->CreateVideoFrame( + decklinkOutput->GetWidth(), decklinkOutput->GetHeight(), + decklinkOutput->GetWidth() * 4, bmdFormat8BitBGRA, + bmdFrameFlagDefault, &decklinkOutputFrame); if (result != S_OK) { blog(LOG_ERROR, "failed to make frame 0x%X", result); return false; @@ -571,8 +560,7 @@ output->DisableVideoOutput(); output->DisableAudioOutput(); - if (decklinkOutputFrame != nullptr) - decklinkOutputFrame = nullptr; + decklinkOutputFrame.Clear(); return true; } @@ -588,12 +576,9 @@ uint8_t *outData = frame->data0; - int rowBytes = decklinkOutput->GetWidth() * 2; - if (device->GetKeyerMode()) { - rowBytes = decklinkOutput->GetWidth() * 4; - } - - std::copy(outData, outData + (decklinkOutput->GetHeight() * rowBytes), + std::copy(outData, + outData + (decklinkOutput->GetWidth() * + decklinkOutput->GetHeight() * 4), destData); output->DisplayVideoFrameSync(decklinkOutputFrame);
View file
obs-studio-28.1.2.tar.xz/plugins/decklink/decklink-output.cpp -> obs-studio-29.0.0.tar.xz/plugins/decklink/decklink-output.cpp
Changed
@@ -81,16 +81,10 @@ decklink->SetSize(mode->GetWidth(), mode->GetHeight()); struct video_scale_info to = {}; - - if (decklink->keyerMode != 0) { - to.format = VIDEO_FORMAT_BGRA; - to.range = VIDEO_RANGE_FULL; - } else { - to.format = VIDEO_FORMAT_UYVY; - to.range = VIDEO_RANGE_PARTIAL; - } + to.format = VIDEO_FORMAT_BGRA; to.width = mode->GetWidth(); to.height = mode->GetHeight(); + to.range = VIDEO_RANGE_FULL; to.colorspace = VIDEO_CS_709; obs_output_set_video_conversion(decklink->GetOutput(), &to);
View file
obs-studio-28.1.2.tar.xz/plugins/image-source/obs-slideshow.c -> obs-studio-29.0.0.tar.xz/plugins/image-source/obs-slideshow.c
Changed
@@ -186,7 +186,14 @@ static inline size_t random_file(struct slideshow *ss) { - return (size_t)rand() % ss->files.num; + size_t next = ss->cur_item; + + if (ss->files.num > 1) { + while (next == ss->cur_item) + next = (size_t)rand() % ss->files.num; + } + + return next; } /* ------------------------------------------------------------------------- */ @@ -343,6 +350,11 @@ const char *path = obs_data_get_string(item, "value"); os_dir_t *dir = os_opendir(path); + if (!path || !*path) { + obs_data_release(item); + continue; + } + if (dir) { struct dstr dir_path = {0}; struct os_dirent *ent; @@ -539,7 +551,9 @@ if (!ss->files.num || obs_transition_get_time(ss->transition) < 1.0f) return; - if (++ss->cur_item >= ss->files.num) + if (ss->randomize) + ss->cur_item = random_file(ss); + else if (++ss->cur_item >= ss->files.num) ss->cur_item = 0; do_transition(ss, false); @@ -552,7 +566,9 @@ if (!ss->files.num || obs_transition_get_time(ss->transition) < 1.0f) return; - if (ss->cur_item == 0) + if (ss->randomize) + ss->cur_item = random_file(ss); + else if (ss->cur_item == 0) ss->cur_item = ss->files.num - 1; else --ss->cur_item; @@ -626,6 +642,18 @@ obs_source_media_previous(ss->source); } +static void current_slide_proc(void *data, calldata_t *cd) +{ + struct slideshow *ss = data; + calldata_set_int(cd, "current_index", ss->cur_item); +} + +static void total_slides_proc(void *data, calldata_t *cd) +{ + struct slideshow *ss = data; + calldata_set_int(cd, "total_files", ss->files.num); +} + static void ss_destroy(void *data) { struct slideshow *ss = data; @@ -639,6 +667,7 @@ static void *ss_create(obs_data_t *settings, obs_source_t *source) { struct slideshow *ss = bzalloc(sizeof(*ss)); + proc_handler_t *ph = obs_source_get_proc_handler(source); ss->source = source; @@ -667,6 +696,9 @@ obs_module_text("SlideShow.PreviousSlide"), previous_slide_hotkey, ss); + proc_handler_add(ph, "int current_index()", current_slide_proc, ss); + proc_handler_add(ph, "int total_files()", total_slides_proc, ss); + pthread_mutex_init_value(&ss->mutex); if (pthread_mutex_init(&ss->mutex, NULL) != 0) goto error; @@ -742,20 +774,7 @@ return; } - if (ss->randomize) { - size_t next = ss->cur_item; - if (ss->files.num > 1) { - while (next == ss->cur_item) - next = random_file(ss); - } - ss->cur_item = next; - - } else if (++ss->cur_item >= ss->files.num) { - ss->cur_item = 0; - } - - if (ss->files.num) - do_transition(ss, false); + obs_source_media_next(ss->source); } } @@ -922,7 +941,7 @@ obs_property_list_add_string(p, aspectsi, aspectsi); char str32; - snprintf(str, 32, "%dx%d", cx, cy); + snprintf(str, sizeof(str), "%dx%d", cx, cy); obs_property_list_add_string(p, str, str); if (ss) { @@ -987,7 +1006,10 @@ const char *path = obs_data_get_string(file, "value"); if (strcmp(path, orig_path) == 0) { - obs_data_set_string(file, "value", new_path); + if (new_path && *new_path) + obs_data_set_string(file, "value", new_path); + else + obs_data_array_erase(files, i); obs_data_release(file); break;
View file
obs-studio-28.1.2.tar.xz/plugins/linux-capture/xshm-input.c -> obs-studio-29.0.0.tar.xz/plugins/linux-capture/xshm-input.c
Changed
@@ -365,7 +365,13 @@ x11_screen_geo(xcb, i, &w, &h); if (name == NULL) { - sprintf(name_tmp, "%" PRIuFAST32, i); + int ret = snprintf(name_tmp, sizeof(name_tmp), + "%" PRIuFAST32, i); + if (ret >= sizeof(name_tmp)) + blog(LOG_DEBUG, + "linux-capture: A format truncation may have occurred." + " This can be ignored since it is quite improbable."); + name = name_tmp; }
View file
obs-studio-28.1.2.tar.xz/plugins/linux-v4l2/v4l2-input.c -> obs-studio-29.0.0.tar.xz/plugins/linux-v4l2/v4l2-input.c
Changed
@@ -416,8 +416,14 @@ /* make sure device names are unique */ char unique_device_name68; - sprintf(unique_device_name, "%s (%s)", video_cap.card, - video_cap.bus_info); + int ret = snprintf(unique_device_name, + sizeof(unique_device_name), "%s (%s)", + video_cap.card, video_cap.bus_info); + if (ret >= sizeof(unique_device_name)) + blog(LOG_DEBUG, + "linux-v4l2: A format truncation may have occurred." + " This can be ignored since it is quite improbable."); + obs_property_list_add_string(prop, unique_device_name, device.array); blog(LOG_INFO, "Found device '%s' at %s", video_cap.card,
View file
obs-studio-28.1.2.tar.xz/plugins/mac-avcapture/av-capture.mm -> obs-studio-29.0.0.tar.xz/plugins/mac-avcapture/av-capture.mm
Changed
@@ -2205,34 +2205,32 @@ OBS_COMBO_FORMAT_STRING); obs_property_list_add_string(dev_list, "", ""); - NSArray *devices = nil; - - AVCaptureDeviceDiscoverySession *mediaDeviceDiscoverySession = AVCaptureDeviceDiscoverySession - discoverySessionWithDeviceTypes:@ - AVCaptureDeviceTypeBuiltInWideAngleCamera, - AVCaptureDeviceTypeExternalUnknown - + NSMutableArray *device_types = NSMutableArray + arrayWithObjects:AVCaptureDeviceTypeBuiltInWideAngleCamera, + AVCaptureDeviceTypeExternalUnknown, nil; +#if __MAC_OS_X_VERSION_MAX_ALLOWED >= 130000 + if (__builtin_available(macOS 13.0, *)) { + device_types addObject:AVCaptureDeviceTypeDeskViewCamera; + } +#endif + AVCaptureDeviceDiscoverySession *video_discovery = AVCaptureDeviceDiscoverySession + discoverySessionWithDeviceTypes:device_types mediaType:AVMediaTypeVideo position:AVCaptureDevicePositionUnspecified; - NSArray *mediaDevices = mediaDeviceDiscoverySession devices; + for (AVCaptureDevice *dev in video_discovery devices) { + obs_property_list_add_string(dev_list, + dev.localizedName.UTF8String, + dev.uniqueID.UTF8String); + } - AVCaptureDeviceDiscoverySession *muxedDeviceDiscoverySession = AVCaptureDeviceDiscoverySession - discoverySessionWithDeviceTypes:@ - AVCaptureDeviceTypeExternalUnknown - + AVCaptureDeviceDiscoverySession *muxed_discovery = AVCaptureDeviceDiscoverySession + discoverySessionWithDeviceTypes:device_types mediaType:AVMediaTypeMuxed position:AVCaptureDevicePositionUnspecified; - NSArray *muxedDevices = muxedDeviceDiscoverySession devices; - - devices = mediaDevices arrayByAddingObjectsFromArray:muxedDevices; - - for (AVCaptureDevice *dev in devices) { - if (dev hasMediaType:AVMediaTypeVideo || - dev hasMediaType:AVMediaTypeMuxed) { - obs_property_list_add_string( - dev_list, dev.localizedName.UTF8String, - dev.uniqueID.UTF8String); - } + for (AVCaptureDevice *dev in muxed_discovery devices) { + obs_property_list_add_string(dev_list, + dev.localizedName.UTF8String, + dev.uniqueID.UTF8String); } obs_property_set_modified_callback(dev_list, properties_device_changed);
View file
obs-studio-28.1.2.tar.xz/plugins/mac-capture/data/locale/en-US.ini -> obs-studio-29.0.0.tar.xz/plugins/mac-capture/data/locale/en-US.ini
Changed
@@ -24,4 +24,5 @@ SCK.Name="macOS Screen Capture" SCK.Name.Beta="macOS Screen Capture (BETA)" SCK.AudioUnavailable="Audio capture requires macOS 13 or newer." +SCK.CaptureTypeUnavailable="Selected capture type requires macOS 13 or newer." SCK.Method="Method"
View file
obs-studio-28.1.2.tar.xz/plugins/mac-capture/mac-display-capture.m -> obs-studio-29.0.0.tar.xz/plugins/mac-capture/mac-display-capture.m
Changed
@@ -605,19 +605,20 @@ __attribute__((unused))) { char dimension_buffer412; char name_buffer256; - sprintf(dimension_buffer0, "%u", - (uint32_t)screen frame.size.width); - sprintf(dimension_buffer1, "%u", - (uint32_t)screen frame.size.height); - sprintf(dimension_buffer2, "%d", - (int32_t)screen frame.origin.x); - sprintf(dimension_buffer3, "%d", - (int32_t)screen frame.origin.y); - - sprintf(name_buffer, "%.200s: %.12sx%.12s @ %.12s,%.12s", - screen localizedName UTF8String, - dimension_buffer0, dimension_buffer1, - dimension_buffer2, dimension_buffer3); + snprintf(dimension_buffer0, sizeof(dimension_buffer0), "%u", + (uint32_t)screen frame.size.width); + snprintf(dimension_buffer1, sizeof(dimension_buffer0), "%u", + (uint32_t)screen frame.size.height); + snprintf(dimension_buffer2, sizeof(dimension_buffer0), "%d", + (int32_t)screen frame.origin.x); + snprintf(dimension_buffer3, sizeof(dimension_buffer0), "%d", + (int32_t)screen frame.origin.y); + + snprintf(name_buffer, sizeof(name_buffer), + "%.200s: %.12sx%.12s @ %.12s,%.12s", + screen localizedName UTF8String, + dimension_buffer0, dimension_buffer1, + dimension_buffer2, dimension_buffer3); obs_property_list_add_int(list, name_buffer, index); };
View file
obs-studio-28.1.2.tar.xz/plugins/mac-capture/mac-screen-capture.m -> obs-studio-29.0.0.tar.xz/plugins/mac-capture/mac-screen-capture.m
Changed
@@ -69,6 +69,8 @@ NSString *application_id; }; +#pragma mark - + static void destroy_screen_stream(struct screen_capture *sc) { if (sc->disp) { @@ -365,33 +367,9 @@ case ScreenCaptureDisplayStream: { SCDisplay *target_display = get_target_display(); - if (@available(macOS 13.0, *)) { - content_filter = SCContentFilter alloc - initWithDisplay:target_display - excludingWindows:NSArray alloc init; - } else { - NSArray *excluded = sc->shareable_content.applications - filteredArrayUsingPredicate: - NSPredicate predicateWithBlock:^BOOL( - SCRunningApplication - *application, - NSDictionary< - NSString *, - id> - *_Nullable bindings - __attribute__(( - unused))) { - return application - .bundleIdentifier - isEqualToString: - @"com.apple.controlcenter"; - }; - - content_filter = SCContentFilter alloc - initWithDisplay:target_display - excludingApplications:excluded - exceptingWindows:NSArray alloc init; - } + content_filter = SCContentFilter alloc + initWithDisplay:target_display + excludingWindows:NSArray alloc init; set_display_mode(sc, target_display); } break; @@ -462,15 +440,24 @@ os_sem_post(sc->shareable_content_available); sc->stream_properties setQueueDepth:8; sc->stream_properties setShowsCursor:!sc->hide_cursor; - sc->stream_properties setColorSpaceName:kCGColorSpaceSRGB; - sc->stream_properties setPixelFormat:'BGRA'; -#if __MAC_OS_X_VERSION_MAX_ALLOWED >= 130000 + sc->stream_properties setColorSpaceName:kCGColorSpaceDisplayP3; + sc->stream_properties setPixelFormat:'l10r'; + if (@available(macOS 13.0, *)) { +#if __MAC_OS_X_VERSION_MAX_ALLOWED >= 130000 sc->stream_properties setCapturesAudio:TRUE; sc->stream_properties setExcludesCurrentProcessAudio:TRUE; sc->stream_properties setChannelCount:2; - } #endif + } else { + if (sc->capture_type != ScreenCaptureWindowStream) { + sc->disp = NULL; + os_event_init(&sc->disp_finished, OS_EVENT_TYPE_MANUAL); + os_event_init(&sc->stream_start_completed, + OS_EVENT_TYPE_MANUAL); + return true; + } + } sc->disp = SCStream alloc initWithFilter:content_filter configuration:sc->stream_properties @@ -491,7 +478,7 @@ } #if __MAC_OS_X_VERSION_MAX_ALLOWED >= 130000 - if (__builtin_available(macOS 13.0, *)) { + if (@available(macOS 13.0, *)) { did_add_output = sc->disp addStreamOutput:sc->capture_delegate type:SCStreamOutputTypeAudio @@ -577,8 +564,8 @@ sc->show_empty_names = obs_data_get_bool(settings, "show_empty_names"); sc->show_hidden_windows = obs_data_get_bool(settings, "show_hidden_windows"); - sc->window = obs_data_get_int(settings, "window"); - sc->capture_type = obs_data_get_int(settings, "type"); + sc->window = (CGWindowID)obs_data_get_int(settings, "window"); + sc->capture_type = (unsigned int)obs_data_get_int(settings, "type"); os_sem_init(&sc->shareable_content_available, 1); screen_capture_build_content_list( @@ -591,7 +578,7 @@ if (!sc->effect) goto fail; - sc->display = obs_data_get_int(settings, "display"); + sc->display = (CGDirectDisplayID)obs_data_get_int(settings, "display"); sc->application_id = NSString alloc initWithUTF8String:obs_data_get_string(settings, "application"); @@ -649,18 +636,13 @@ if (!sc->tex) return; - const bool linear_srgb = gs_get_linear_srgb(); - const bool previous = gs_framebuffer_srgb_enabled(); - gs_enable_framebuffer_srgb(linear_srgb); + gs_enable_framebuffer_srgb(true); gs_eparam_t *param = gs_effect_get_param_by_name(sc->effect, "image"); - if (linear_srgb) - gs_effect_set_texture_srgb(param, sc->tex); - else - gs_effect_set_texture(param, sc->tex); + gs_effect_set_texture(param, sc->tex); - while (gs_effect_loop(sc->effect, "Draw")) + while (gs_effect_loop(sc->effect, "DrawD65P3")) gs_draw_sprite(sc->tex, 0, 0, 0); gs_enable_framebuffer_srgb(previous); @@ -704,10 +686,11 @@ } } - obs_data_set_default_int(settings, "type", 0); obs_data_set_default_int(settings, "display", initial_display); - obs_data_set_default_int(settings, "window", kCGNullWindowID); + obs_data_set_default_obj(settings, "application", NULL); + obs_data_set_default_int(settings, "type", ScreenCaptureDisplayStream); + obs_data_set_default_int(settings, "window", kCGNullWindowID); obs_data_set_default_bool(settings, "show_cursor", true); obs_data_set_default_bool(settings, "show_empty_names", false); obs_data_set_default_bool(settings, "show_hidden_windows", false); @@ -718,7 +701,8 @@ struct screen_capture *sc = data; CGWindowID old_window_id = sc->window; - CGWindowID new_window_id = obs_data_get_int(settings, "window"); + CGWindowID new_window_id = + (CGWindowID)obs_data_get_int(settings, "window"); if (new_window_id > 0 && new_window_id != old_window_id) sc->window = new_window_id; @@ -771,6 +755,8 @@ obs_leave_graphics(); } +#pragma mark - obs_properties + static bool build_display_list(struct screen_capture *sc, obs_properties_t *props) { @@ -805,19 +791,20 @@ char dimension_buffer412 = {}; char name_buffer256 = {}; - sprintf(dimension_buffer0, "%u", - (uint32_t)screen.frame.size.width); - sprintf(dimension_buffer1, "%u", - (uint32_t)screen.frame.size.height); - sprintf(dimension_buffer2, "%d", - (int32_t)screen.frame.origin.x); - sprintf(dimension_buffer3, "%d", - (int32_t)screen.frame.origin.y); - - sprintf(name_buffer, "%.200s: %.12sx%.12s @ %.12s,%.12s", - screen.localizedName.UTF8String, dimension_buffer0, - dimension_buffer1, dimension_buffer2, - dimension_buffer3); + snprintf(dimension_buffer0, sizeof(dimension_buffer0), "%u", + (uint32_t)screen.frame.size.width); + snprintf(dimension_buffer1, sizeof(dimension_buffer0), "%u", + (uint32_t)screen.frame.size.height); + snprintf(dimension_buffer2, sizeof(dimension_buffer0), "%d", + (int32_t)screen.frame.origin.x); + snprintf(dimension_buffer3, sizeof(dimension_buffer0), "%d", + (int32_t)screen.frame.origin.y); + + snprintf(name_buffer, sizeof(name_buffer), + "%.200s: %.12sx%.12s @ %.12s,%.12s", + screen.localizedName.UTF8String, dimension_buffer0, + dimension_buffer1, dimension_buffer2, + dimension_buffer3); obs_property_list_add_int(display_list, name_buffer, display.displayID); @@ -898,7 +885,8 @@ { struct screen_capture *sc = data; - unsigned int capture_type_id = obs_data_get_int(settings, "type"); + unsigned int capture_type_id = + (unsigned int)obs_data_get_int(settings, "type"); obs_property_t *display_list = obs_properties_get(props, "display"); obs_property_t *window_list = obs_properties_get(props, "window"); obs_property_t *app_list = obs_properties_get(props, "application"); @@ -906,6 +894,9 @@ obs_property_t *hidden = obs_properties_get(props, "show_hidden_windows"); + obs_property_t *capture_type_error = + obs_properties_get(props, "capture_type_info"); + if (sc->capture_type != capture_type_id) { switch (capture_type_id) { case 0: { @@ -914,6 +905,11 @@ obs_property_set_visible(app_list, false); obs_property_set_visible(empty, false); obs_property_set_visible(hidden, false); + + if (capture_type_error) { + obs_property_set_visible(capture_type_error, + true); + } break; } case 1: { @@ -922,6 +918,11 @@ obs_property_set_visible(app_list, false); obs_property_set_visible(empty, true); obs_property_set_visible(hidden, true); + + if (capture_type_error) { + obs_property_set_visible(capture_type_error, + false); + } break; } case 2: { @@ -930,21 +931,26 @@ obs_property_set_visible(window_list, false); obs_property_set_visible(empty, false); obs_property_set_visible(hidden, true); + + if (capture_type_error) { + obs_property_set_visible(capture_type_error, + true); + } break; } } } - sc->show_empty_names = obs_data_get_bool(settings, "show_empty_names"); - sc->show_hidden_windows = - obs_data_get_bool(settings, "show_hidden_windows"); - screen_capture_build_content_list( sc, capture_type_id == ScreenCaptureDisplayStream); build_display_list(sc, props); build_window_list(sc, props); build_application_list(sc, props); + sc->show_empty_names = obs_data_get_bool(settings, "show_empty_names"); + sc->show_hidden_windows = + obs_data_get_bool(settings, "show_hidden_windows"); + return true; } @@ -953,9 +959,11 @@ struct screen_capture *sc = data; obs_properties_t *props = obs_properties_create(); + obs_property_t *capture_type = obs_properties_add_list( props, "type", obs_module_text("SCK.Method"), OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT); + obs_property_list_add_int(capture_type, obs_module_text("DisplayCapture"), 0); obs_property_list_add_int(capture_type, @@ -986,9 +994,6 @@ props, "show_hidden_windows", obs_module_text("WindowUtils.ShowHidden")); - obs_properties_add_bool(props, "show_cursor", - obs_module_text("DisplayCapture.ShowCursor")); - if (sc) { obs_property_set_modified_callback2( hidden, content_settings_changed, sc); @@ -1024,16 +1029,77 @@ empty, content_settings_changed, sc); } + obs_properties_add_bool(props, "show_cursor", + obs_module_text("DisplayCapture.ShowCursor")); + if (@available(macOS 13.0, *)) ; - else - obs_properties_add_text(props, "audio_info", - obs_module_text("SCK.AudioUnavailable"), - OBS_TEXT_INFO); + else { + obs_property_t *audio_warning = obs_properties_add_text( + props, "audio_info", + obs_module_text("SCK.AudioUnavailable"), OBS_TEXT_INFO); + obs_property_text_set_info_type(audio_warning, + OBS_TEXT_INFO_WARNING); + + obs_property_t *capture_type_error = obs_properties_add_text( + props, "capture_type_info", + obs_module_text("SCK.CaptureTypeUnavailable"), + OBS_TEXT_INFO); + + obs_property_text_set_info_type(capture_type_error, + OBS_TEXT_INFO_ERROR); + + if (sc) { + switch (sc->capture_type) { + case ScreenCaptureDisplayStream: { + obs_property_set_visible(capture_type_error, + true); + break; + } + case ScreenCaptureWindowStream: { + obs_property_set_visible(capture_type_error, + false); + break; + } + case ScreenCaptureApplicationStream: { + obs_property_set_visible(capture_type_error, + true); + break; + } + } + } else { + obs_property_set_visible(capture_type_error, false); + } + } return props; } +enum gs_color_space screen_capture_video_get_color_space( + void *data, size_t count, const enum gs_color_space *preferred_spaces) +{ + UNUSED_PARAMETER(data); + + for (size_t i = 0; i < count; ++i) { + if (preferred_spacesi == GS_CS_SRGB_16F) + return GS_CS_SRGB_16F; + } + + for (size_t i = 0; i < count; ++i) { + if (preferred_spacesi == GS_CS_709_EXTENDED) + return GS_CS_709_EXTENDED; + } + + for (size_t i = 0; i < count; ++i) { + if (preferred_spacesi == GS_CS_SRGB) + return GS_CS_SRGB; + } + + return GS_CS_SRGB_16F; +} + +#pragma mark - obs_source_info + struct obs_source_info screen_capture_info = { .id = "screen_capture", .type = OBS_SOURCE_TYPE_INPUT, @@ -1055,8 +1121,11 @@ .get_properties = screen_capture_properties, .update = screen_capture_update, .icon_type = OBS_ICON_TYPE_DESKTOP_CAPTURE, + .video_get_color_space = screen_capture_video_get_color_space, }; +#pragma mark - ScreenCaptureDelegate + @implementation ScreenCaptureDelegate - (void)stream:(SCStream *)stream
View file
obs-studio-28.1.2.tar.xz/plugins/mac-videotoolbox/data/locale/en-US.ini -> obs-studio-29.0.0.tar.xz/plugins/mac-videotoolbox/data/locale/en-US.ini
Changed
@@ -1,5 +1,11 @@ VTH264EncHW="Apple VT H264 Hardware Encoder" VTH264EncSW="Apple VT H264 Software Encoder" +VTHEVCEncHW="Apple VT HEVC Hardware Encoder" +VTHEVCEncT2="Apple VT HEVC T2 Hardware Encoder" +VTHEVCEncSW="Apple VT HEVC Software Encoder" +VTProResEncHW="Apple VT ProRes Hardware Encoder" +VTProResEncSW="Apple VT ProRes Software Encoder" +VTEncoder="VideoToolbox Encoder" Bitrate="Bitrate" Quality="Quality" UseMaxBitrate="Limit bitrate" @@ -9,4 +15,9 @@ Profile="Profile" UseBFrames="Use B-Frames" RateControl="Rate Control" -ColorFormatUnsupportedH264="The selected color format is not supported by the Apple VT H.264 encoder. Select a compatible color format in Settings -> Advanced or use a different encoder." +ColorFormatUnsupported="The selected color format is not supported by the selected Apple VT encoder. Select a compatible color format in Settings -> Advanced or use a different encoder." +ProResCodec="ProRes Codec" +ProRes422Proxy="ProRes 422 Proxy" +ProRes422LT="ProRes 422 LT" +ProRes422="ProRes 422" +ProRes422HQ="ProRes 422 HQ"
View file
obs-studio-28.1.2.tar.xz/plugins/mac-videotoolbox/encoder.c -> obs-studio-29.0.0.tar.xz/plugins/mac-videotoolbox/encoder.c
Changed
@@ -14,18 +14,28 @@ #define VT_LOG(level, format, ...) \ blog(level, "VideoToolbox encoder: " format, ##__VA_ARGS__) -#define VT_LOG_ENCODER(encoder, level, format, ...) \ - blog(level, "VideoToolbox %s: 'h264': " format, \ - obs_encoder_get_name(encoder), ##__VA_ARGS__) -#define VT_BLOG(level, format, ...) \ - VT_LOG_ENCODER(enc->encoder, level, format, ##__VA_ARGS__) +#define VT_LOG_ENCODER(encoder, codec_type, level, format, ...) \ + blog(level, "VideoToolbox %s: '%s': " format, \ + obs_encoder_get_name(encoder), \ + codec_type_to_print_fmt(codec_type), ##__VA_ARGS__) +#define VT_BLOG(level, format, ...) \ + VT_LOG_ENCODER(enc->encoder, enc->codec_type, level, format, \ + ##__VA_ARGS__) struct vt_encoder_type_data { const char *disp_name; const char *id; + CMVideoCodecType codec_type; bool hardware_accelerated; }; +struct vt_prores_encoder_data { + FourCharCode codec_type; + CFStringRef encoder_id; +}; +static DARRAY(struct vt_prores_encoder_data) vt_prores_hardware_encoder_list; +static DARRAY(struct vt_prores_encoder_data) vt_prores_software_encoder_list; + struct vt_encoder { obs_encoder_t *encoder; @@ -42,6 +52,7 @@ uint32_t rc_max_bitrate; float rc_max_bitrate_window; const char *profile; + CMVideoCodecType codec_type; bool bframes; int vt_pix_fmt; @@ -54,6 +65,26 @@ DARRAY(uint8_t) extra_data; }; +static const char *codec_type_to_print_fmt(CMVideoCodecType codec_type) +{ + switch (codec_type) { + case kCMVideoCodecType_H264: + return "h264"; + case kCMVideoCodecType_HEVC: + return "hevc"; + case kCMVideoCodecType_AppleProRes422Proxy: + return "apco"; + case kCMVideoCodecType_AppleProRes422LT: + return "apcs"; + case kCMVideoCodecType_AppleProRes422: + return "apcn"; + case kCMVideoCodecType_AppleProRes422HQ: + return "apch"; + default: + return ""; + } +} + static void log_osstatus(int log_level, struct vt_encoder *enc, const char *context, OSStatus code) { @@ -75,26 +106,134 @@ CFRelease(err); } -static CFStringRef obs_to_vt_profile(const char *profile) +static CFStringRef obs_to_vt_profile(CMVideoCodecType codec_type, + const char *profile, + enum video_format format) { - if (strcmp(profile, "baseline") == 0) + if (codec_type == kCMVideoCodecType_H264) { + if (strcmp(profile, "baseline") == 0) + return kVTProfileLevel_H264_Baseline_AutoLevel; + else if (strcmp(profile, "main") == 0) + return kVTProfileLevel_H264_Main_AutoLevel; + else if (strcmp(profile, "high") == 0) + return kVTProfileLevel_H264_High_AutoLevel; + else + return kVTProfileLevel_H264_Main_AutoLevel; +#ifdef ENABLE_HEVC + } else if (codec_type == kCMVideoCodecType_HEVC) { + if (strcmp(profile, "main") == 0) { + if (format == VIDEO_FORMAT_P010) { + VT_LOG(LOG_WARNING, "Forcing main10 for P010"); + return kVTProfileLevel_HEVC_Main10_AutoLevel; + } else { + return kVTProfileLevel_HEVC_Main_AutoLevel; + } + } + if (strcmp(profile, "main10") == 0) + return kVTProfileLevel_HEVC_Main10_AutoLevel; +#if __MAC_OS_X_VERSION_MAX_ALLOWED >= 120300 // macOS 12.3 + if (__builtin_available(macOS 12.3, *)) { + if (strcmp(profile, "main42210") == 0) + return kVTProfileLevel_HEVC_Main42210_AutoLevel; + } +#endif // macOS 12.3 + return kVTProfileLevel_HEVC_Main_AutoLevel; +#endif // ENABLE_HEVC + } else { return kVTProfileLevel_H264_Baseline_AutoLevel; - else if (strcmp(profile, "main") == 0) - return kVTProfileLevel_H264_Main_AutoLevel; - else if (strcmp(profile, "high") == 0) - return kVTProfileLevel_H264_High_AutoLevel; - else - return kVTProfileLevel_H264_Main_AutoLevel; + } } static CFStringRef obs_to_vt_colorspace(enum video_colorspace cs) { - if (cs == VIDEO_CS_709) - return kCVImageBufferYCbCrMatrix_ITU_R_709_2; - else if (cs == VIDEO_CS_601) + switch (cs) { + case VIDEO_CS_601: return kCVImageBufferYCbCrMatrix_ITU_R_601_4; + case VIDEO_CS_2100_PQ: + case VIDEO_CS_2100_HLG: + return kCVImageBufferYCbCrMatrix_ITU_R_2020; + default: + return kCVImageBufferYCbCrMatrix_ITU_R_709_2; + } +} - return NULL; +static CFStringRef obs_to_vt_primaries(enum video_colorspace cs) +{ + switch (cs) { + case VIDEO_CS_601: + return kCVImageBufferColorPrimaries_SMPTE_C; + case VIDEO_CS_2100_PQ: + case VIDEO_CS_2100_HLG: + return kCVImageBufferColorPrimaries_ITU_R_2020; + default: + return kCVImageBufferColorPrimaries_ITU_R_709_2; + } +} + +static CFStringRef obs_to_vt_transfer(enum video_colorspace cs) +{ + switch (cs) { + case VIDEO_CS_SRGB: + return kCVImageBufferTransferFunction_sRGB; + case VIDEO_CS_2100_PQ: + return kCVImageBufferTransferFunction_SMPTE_ST_2084_PQ; + case VIDEO_CS_2100_HLG: + return kCVImageBufferTransferFunction_ITU_R_2100_HLG; + default: + return kCVImageBufferTransferFunction_ITU_R_709_2; + } +} + +/* Adapted from Chromium GenerateMasteringDisplayColorVolume */ +static CFDataRef obs_to_vt_masteringdisplay(uint32_t hdr_nominal_peak_level) +{ + struct mastering_display_colour_volume { + uint16_t display_primaries32; + uint16_t white_point2; + uint32_t max_display_mastering_luminance; + uint32_t min_display_mastering_luminance; + }; + static_assert(sizeof(struct mastering_display_colour_volume) == 24, + "May need to adjust struct packing"); + + struct mastering_display_colour_volume mdcv; + mdcv.display_primaries00 = __builtin_bswap16(13250); + mdcv.display_primaries01 = __builtin_bswap16(34500); + mdcv.display_primaries10 = __builtin_bswap16(7500); + mdcv.display_primaries11 = __builtin_bswap16(3000); + mdcv.display_primaries20 = __builtin_bswap16(34000); + mdcv.display_primaries21 = __builtin_bswap16(16000); + mdcv.white_point0 = __builtin_bswap16(15635); + mdcv.white_point1 = __builtin_bswap16(16450); + mdcv.max_display_mastering_luminance = + __builtin_bswap32(hdr_nominal_peak_level * 10000); + mdcv.min_display_mastering_luminance = 0; + + UInt8 bytessizeof(struct mastering_display_colour_volume); + memcpy(bytes, &mdcv, sizeof(bytes)); + return CFDataCreate(NULL, bytes, sizeof(bytes)); +} + +/* Adapted from Chromium GenerateContentLightLevelInfo */ +static CFDataRef +obs_to_vt_contentlightlevelinfo(uint16_t hdr_nominal_peak_level) +{ + struct content_light_level_info { + uint16_t max_content_light_level; + uint16_t max_pic_average_light_level; + }; + static_assert(sizeof(struct content_light_level_info) == 4, + "May need to adjust struct packing"); + + struct content_light_level_info clli; + clli.max_content_light_level = + __builtin_bswap16(hdr_nominal_peak_level); + clli.max_pic_average_light_level = + __builtin_bswap16(hdr_nominal_peak_level); + + UInt8 bytessizeof(struct content_light_level_info); + memcpy(bytes, &clli, sizeof(bytes)); + return CFDataCreate(NULL, bytes, sizeof(bytes)); } #define STATUS_CHECK(c) \ @@ -253,19 +392,31 @@ static OSStatus session_set_colorspace(VTCompressionSessionRef session, enum video_colorspace cs) { - CFStringRef matrix = obs_to_vt_colorspace(cs); OSStatus code; - - if (matrix != NULL) { - SESSION_CHECK(session_set_prop( - session, kVTCompressionPropertyKey_ColorPrimaries, - kCVImageBufferColorPrimaries_ITU_R_709_2)); + SESSION_CHECK(session_set_prop(session, + kVTCompressionPropertyKey_ColorPrimaries, + obs_to_vt_primaries(cs))); + SESSION_CHECK(session_set_prop( + session, kVTCompressionPropertyKey_TransferFunction, + obs_to_vt_transfer(cs))); + SESSION_CHECK(session_set_prop(session, + kVTCompressionPropertyKey_YCbCrMatrix, + obs_to_vt_colorspace(cs))); + const bool pq = cs == VIDEO_CS_2100_PQ; + const bool hlg = cs == VIDEO_CS_2100_HLG; + if (pq || hlg) { + const uint16_t hdr_nominal_peak_level = + pq ? (uint16_t)obs_get_video_hdr_nominal_peak_level() + : (hlg ? 1000 : 0); SESSION_CHECK(session_set_prop( - session, kVTCompressionPropertyKey_TransferFunction, - kCVImageBufferTransferFunction_ITU_R_709_2)); + session, + kVTCompressionPropertyKey_MasteringDisplayColorVolume, + obs_to_vt_masteringdisplay(hdr_nominal_peak_level))); SESSION_CHECK(session_set_prop( - session, kVTCompressionPropertyKey_YCbCrMatrix, - matrix)); + session, + kVTCompressionPropertyKey_ContentLightLevelInfo, + obs_to_vt_contentlightlevelinfo( + hdr_nominal_peak_level))); } return noErr; @@ -289,10 +440,6 @@ CFRelease(pixbuf); } #define ENCODER_ID kVTVideoEncoderSpecification_EncoderID -#define ENABLE_HW_ACCEL \ - kVTVideoEncoderSpecification_EnableHardwareAcceleratedVideoEncoder -#define REQUIRE_HW_ACCEL \ - kVTVideoEncoderSpecification_RequireHardwareAcceleratedVideoEncoder static inline CFMutableDictionaryRef create_encoder_spec(const char *vt_encoder_id) { @@ -305,14 +452,40 @@ CFDictionaryAddValue(encoder_spec, ENCODER_ID, id); CFRelease(id); - CFDictionaryAddValue(encoder_spec, ENABLE_HW_ACCEL, kCFBooleanTrue); - CFDictionaryAddValue(encoder_spec, REQUIRE_HW_ACCEL, kCFBooleanFalse); + return encoder_spec; +} + +static inline CFMutableDictionaryRef +create_prores_encoder_spec(CMVideoCodecType target_codec_type, + bool hardware_accelerated) +{ + CFStringRef encoder_id = NULL; + + size_t size = 0; + struct vt_prores_encoder_data *encoder_list = NULL; + if (hardware_accelerated) { + size = vt_prores_hardware_encoder_list.num; + encoder_list = vt_prores_hardware_encoder_list.array; + } else { + size = vt_prores_software_encoder_list.num; + encoder_list = vt_prores_software_encoder_list.array; + } + + for (size_t i = 0; i < size; ++i) { + if (target_codec_type == encoder_listi.codec_type) { + encoder_id = encoder_listi.encoder_id; + } + } + + CFMutableDictionaryRef encoder_spec = CFDictionaryCreateMutable( + kCFAllocatorDefault, 1, &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + + CFDictionaryAddValue(encoder_spec, ENCODER_ID, encoder_id); return encoder_spec; } #undef ENCODER_ID -#undef REQUIRE_HW_ACCEL -#undef ENABLE_HW_ACCEL static inline CFMutableDictionaryRef create_pixbuf_spec(struct vt_encoder *enc) { @@ -342,13 +515,25 @@ VTCompressionSessionRef s; - CFDictionaryRef encoder_spec = create_encoder_spec(enc->vt_encoder_id); + const char *codec_name = obs_encoder_get_codec(enc->encoder); + + CFDictionaryRef encoder_spec; + if (strcmp(codec_name, "prores") == 0) { + struct vt_encoder_type_data *type_data = + (struct vt_encoder_type_data *) + obs_encoder_get_type_data(enc->encoder); + encoder_spec = create_prores_encoder_spec( + enc->codec_type, type_data->hardware_accelerated); + } else { + encoder_spec = create_encoder_spec(enc->vt_encoder_id); + } + CFDictionaryRef pixbuf_spec = create_pixbuf_spec(enc); STATUS_CHECK(VTCompressionSessionCreate( - kCFAllocatorDefault, enc->width, enc->height, - kCMVideoCodecType_H264, encoder_spec, pixbuf_spec, NULL, - &sample_encoded_callback, enc->queue, &s)); + kCFAllocatorDefault, enc->width, enc->height, enc->codec_type, + encoder_spec, pixbuf_spec, NULL, &sample_encoded_callback, + enc->queue, &s)); CFRelease(encoder_spec); CFRelease(pixbuf_spec); @@ -367,18 +552,43 @@ if (b != NULL) CFRelease(b); - STATUS_CHECK(session_set_prop_int( - s, kVTCompressionPropertyKey_MaxKeyFrameIntervalDuration, - enc->keyint)); - STATUS_CHECK(session_set_prop_int( - s, kVTCompressionPropertyKey_MaxKeyFrameInterval, - enc->keyint * ((float)enc->fps_num / enc->fps_den))); - STATUS_CHECK(session_set_prop_float( - s, kVTCompressionPropertyKey_ExpectedFrameRate, - (float)enc->fps_num / enc->fps_den)); - STATUS_CHECK(session_set_prop( - s, kVTCompressionPropertyKey_AllowFrameReordering, - enc->bframes ? kCFBooleanTrue : kCFBooleanFalse)); + if (enc->codec_type == kCMVideoCodecType_H264 || + enc->codec_type == kCMVideoCodecType_HEVC) { + + // This can fail when using GPU hardware encoding + code = session_set_prop_int( + s, + kVTCompressionPropertyKey_MaxKeyFrameIntervalDuration, + enc->keyint); + if (code != noErr) + log_osstatus( + LOG_WARNING, enc, + "setting kVTCompressionPropertyKey_MaxKeyFrameIntervalDuration failed, " + "keyframe interval might be incorrect", + code); + + STATUS_CHECK(session_set_prop_int( + s, kVTCompressionPropertyKey_MaxKeyFrameInterval, + enc->keyint * ((float)enc->fps_num / enc->fps_den))); + STATUS_CHECK(session_set_prop_float( + s, kVTCompressionPropertyKey_ExpectedFrameRate, + (float)enc->fps_num / enc->fps_den)); + STATUS_CHECK(session_set_prop( + s, kVTCompressionPropertyKey_AllowFrameReordering, + enc->bframes ? kCFBooleanTrue : kCFBooleanFalse)); + + video_t *video = obs_encoder_video(enc->encoder); + const struct video_output_info *voi = + video_output_get_info(video); + STATUS_CHECK(session_set_prop( + s, kVTCompressionPropertyKey_ProfileLevel, + obs_to_vt_profile(enc->codec_type, enc->profile, + voi->format))); + STATUS_CHECK(session_set_bitrate( + s, enc->rate_control, enc->bitrate, enc->quality, + enc->limit_bitrate, enc->rc_max_bitrate, + enc->rc_max_bitrate_window)); + } // This can fail depending on hardware configuration code = session_set_prop(s, kVTCompressionPropertyKey_RealTime, @@ -390,14 +600,6 @@ "frame delay might be increased", code); - STATUS_CHECK(session_set_prop(s, kVTCompressionPropertyKey_ProfileLevel, - obs_to_vt_profile(enc->profile))); - - STATUS_CHECK(session_set_bitrate(s, enc->rate_control, enc->bitrate, - enc->quality, enc->limit_bitrate, - enc->rc_max_bitrate, - enc->rc_max_bitrate_window)); - STATUS_CHECK(session_set_colorspace(s, enc->colorspace)); STATUS_CHECK(VTCompressionSessionPrepareToEncodeFrames(s)); @@ -447,14 +649,16 @@ "\trc_max_bitrate: %d (kbps)\n" "\trc_max_bitrate_window: %f (s)\n" "\thw_enc: %s\n" - "\tprofile: %s\n", + "\tprofile: %s\n" + "\tcodec_type: %.4s\n", enc->vt_encoder_id, enc->rate_control, enc->bitrate, enc->quality, enc->fps_num, enc->fps_den, enc->width, enc->height, enc->keyint, enc->limit_bitrate ? "on" : "off", enc->rc_max_bitrate, enc->rc_max_bitrate_window, enc->hw_enc ? "on" : "off", (enc->profile != NULL && !!strlen(enc->profile)) ? enc->profile - : "default"); + : "default", + codec_type_to_print_fmt(enc->codec_type)); } static bool set_video_format(struct vt_encoder *enc, enum video_format format, @@ -474,9 +678,20 @@ ? kCVPixelFormatType_420YpCbCr8BiPlanarFullRange : kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange; return true; + case VIDEO_FORMAT_P010: + if (enc->codec_type == kCMVideoCodecType_HEVC) { + enc->vt_pix_fmt = + full_range + ? kCVPixelFormatType_420YpCbCr10BiPlanarFullRange + : kCVPixelFormatType_420YpCbCr10BiPlanarVideoRange; + return true; + } else { + return false; + } default: return false; } + return false; } static bool update_params(struct vt_encoder *enc, obs_data_t *settings) @@ -484,10 +699,24 @@ video_t *video = obs_encoder_video(enc->encoder); const struct video_output_info *voi = video_output_get_info(video); + const char *codec = obs_encoder_get_codec(enc->encoder); + if (strcmp(codec, "h264") == 0) { + enc->codec_type = kCMVideoCodecType_H264; + obs_data_set_int(settings, "codec_type", enc->codec_type); +#ifdef ENABLE_HEVC + } else if (strcmp(codec, "hevc") == 0) { + enc->codec_type = kCMVideoCodecType_HEVC; + obs_data_set_int(settings, "codec_type", enc->codec_type); +#endif + } else { + enc->codec_type = (CMVideoCodecType)obs_data_get_int( + settings, "codec_type"); + } + if (!set_video_format(enc, voi->format, voi->range)) { obs_encoder_set_last_error( enc->encoder, - obs_module_text("ColorFormatUnsupportedH264")); + obs_module_text("ColorFormatUnsupported")); VT_BLOG(LOG_WARNING, "Unsupported color format selected"); return false; } @@ -506,6 +735,7 @@ enc->rc_max_bitrate_window = obs_data_get_double(settings, "max_bitrate_window"); enc->bframes = obs_data_get_bool(settings, "bframes"); + return true; } @@ -574,6 +804,32 @@ packet_put(packet, &annexb_startcode4 - size, size); } +static bool handle_prores_packet(struct vt_encoder *enc, + CMSampleBufferRef buffer) +{ + OSStatus err = 0; + size_t block_size = 0; + uint8_t *block_buf = NULL; + + CMBlockBufferRef block = CMSampleBufferGetDataBuffer(buffer); + if (block == NULL) { + VT_BLOG(LOG_ERROR, + "Failed to get block buffer for ProRes frame."); + return false; + } + err = CMBlockBufferGetDataPointer(block, 0, NULL, &block_size, + (char **)&block_buf); + if (err != 0) { + VT_BLOG(LOG_ERROR, + "Failed to get data buffer pointer for ProRes frame."); + return false; + } + + packet_put(&enc->packet_data.da, block_buf, block_size); + + return true; +} + static void convert_block_nals_to_annexb(struct vt_encoder *enc, struct darray *packet, CMBlockBufferRef block, @@ -626,8 +882,17 @@ size_t param_size; for (size_t i = 0; i < param_count; i++) { - code = CMVideoFormatDescriptionGetH264ParameterSetAtIndex( - format_desc, i, ¶m, ¶m_size, NULL, NULL); + if (enc->codec_type == kCMVideoCodecType_H264) { + code = CMVideoFormatDescriptionGetH264ParameterSetAtIndex( + format_desc, i, ¶m, ¶m_size, NULL, + NULL); +#ifdef ENABLE_HEVC + } else if (enc->codec_type == kCMVideoCodecType_HEVC) { + code = CMVideoFormatDescriptionGetHEVCParameterSetAtIndex( + format_desc, i, ¶m, ¶m_size, NULL, + NULL); +#endif + } if (code != noErr) { log_osstatus(LOG_ERROR, enc, "getting NAL parameter " @@ -659,8 +924,17 @@ size_t param_count; int nal_length_bytes; - code = CMVideoFormatDescriptionGetH264ParameterSetAtIndex( - format_desc, 0, NULL, NULL, ¶m_count, &nal_length_bytes); + if (enc->codec_type == kCMVideoCodecType_H264) { + code = CMVideoFormatDescriptionGetH264ParameterSetAtIndex( + format_desc, 0, NULL, NULL, ¶m_count, + &nal_length_bytes); +#ifdef ENABLE_HEVC + } else if (enc->codec_type == kCMVideoCodecType_HEVC) { + code = CMVideoFormatDescriptionGetHEVCParameterSetAtIndex( + format_desc, 0, NULL, NULL, ¶m_count, + &nal_length_bytes); +#endif + } // it is not clear what errors this function can return // so we check the two most reasonable if (code == kCMFormatDescriptionBridgeError_InvalidParameter || @@ -706,8 +980,6 @@ static bool parse_sample(struct vt_encoder *enc, CMSampleBufferRef buffer, struct encoder_packet *packet, CMTime off) { - int type; - CMTime pts = CMSampleBufferGetPresentationTimeStamp(buffer); CMTime dts = CMSampleBufferGetDecodeTimeStamp(buffer); @@ -720,7 +992,12 @@ pts = CMTimeMultiply(pts, enc->fps_num); dts = CMTimeMultiply(dts, enc->fps_num); - bool keyframe = is_sample_keyframe(buffer); + const bool is_avc = enc->codec_type == kCMVideoCodecType_H264; + const bool has_annexb = is_avc || + (enc->codec_type == kCMVideoCodecType_HEVC); + + // All ProRes frames are "keyframes" + const bool keyframe = !has_annexb || is_sample_keyframe(buffer); da_resize(enc->packet_data, 0); @@ -729,9 +1006,14 @@ if (enc->extra_data.num == 0) extra_data = &enc->extra_data.da; - if (!convert_sample_to_annexb(enc, &enc->packet_data.da, extra_data, - buffer, keyframe)) - goto fail; + if (has_annexb) { + if (!convert_sample_to_annexb(enc, &enc->packet_data.da, + extra_data, buffer, keyframe)) + goto fail; + } else { + if (!handle_prores_packet(enc, buffer)) + goto fail; + } packet->type = OBS_ENCODER_VIDEO; packet->pts = (int64_t)(CMTimeGetSeconds(pts)); @@ -740,35 +1022,40 @@ packet->size = enc->packet_data.num; packet->keyframe = keyframe; - // VideoToolbox produces packets with priority lower than the RTMP code - // expects, which causes it to be unable to recover from frame drops. - // Fix this by manually adjusting the priority. - uint8_t *start = enc->packet_data.array; - uint8_t *end = start + enc->packet_data.num; - - start = (uint8_t *)obs_avc_find_startcode(start, end); - while (true) { - while (start < end && !*(start++)) - ; + if (is_avc) { + // VideoToolbox produces packets with priority lower than the RTMP code + // expects, which causes it to be unable to recover from frame drops. + // Fix this by manually adjusting the priority. + uint8_t *start = enc->packet_data.array; + uint8_t *end = start + enc->packet_data.num; - if (start == end) - break; + start = (uint8_t *)obs_avc_find_startcode(start, end); + while (true) { + while (start < end && !*(start++)) + ; + + if (start == end) + break; + + const int type = start0 & 0x1F; + if (type == OBS_NAL_SLICE_IDR || + type == OBS_NAL_SLICE) { + uint8_t prev_type = (start0 >> 5) & 0x3; + start0 &= ~(3 << 5); + + if (type == OBS_NAL_SLICE_IDR) + start0 |= OBS_NAL_PRIORITY_HIGHEST + << 5; + else if (type == OBS_NAL_SLICE && + prev_type != + OBS_NAL_PRIORITY_DISPOSABLE) + start0 |= OBS_NAL_PRIORITY_HIGH << 5; + else + start0 |= prev_type << 5; + } - type = start0 & 0x1F; - if (type == OBS_NAL_SLICE_IDR || type == OBS_NAL_SLICE) { - uint8_t prev_type = (start0 >> 5) & 0x3; - start0 &= ~(3 << 5); - - if (type == OBS_NAL_SLICE_IDR) - start0 |= OBS_NAL_PRIORITY_HIGHEST << 5; - else if (type == OBS_NAL_SLICE && - prev_type != OBS_NAL_PRIORITY_DISPOSABLE) - start0 |= OBS_NAL_PRIORITY_HIGH << 5; - else - start0 |= prev_type << 5; + start = (uint8_t *)obs_avc_find_startcode(start, end); } - - start = (uint8_t *)obs_avc_find_startcode(start, end); } CFRelease(buffer); @@ -794,16 +1081,31 @@ // I would have expected pixel buffers from the session's // pool to have the correct color space stuff set - CFStringRef matrix = obs_to_vt_colorspace(enc->colorspace); - - CVBufferSetAttachment(pixbuf, kCVImageBufferYCbCrMatrixKey, matrix, + const enum video_colorspace cs = enc->colorspace; + CVBufferSetAttachment(pixbuf, kCVImageBufferYCbCrMatrixKey, + obs_to_vt_colorspace(cs), kCVAttachmentMode_ShouldPropagate); CVBufferSetAttachment(pixbuf, kCVImageBufferColorPrimariesKey, - kCVImageBufferColorPrimaries_ITU_R_709_2, + obs_to_vt_primaries(cs), kCVAttachmentMode_ShouldPropagate); CVBufferSetAttachment(pixbuf, kCVImageBufferTransferFunctionKey, - kCVImageBufferTransferFunction_ITU_R_709_2, + obs_to_vt_transfer(cs), kCVAttachmentMode_ShouldPropagate); + const bool pq = cs == VIDEO_CS_2100_PQ; + const bool hlg = cs == VIDEO_CS_2100_HLG; + if (pq || hlg) { + const uint16_t hdr_nominal_peak_level = + pq ? (uint16_t)obs_get_video_hdr_nominal_peak_level() + : (hlg ? 1000 : 0); + CVBufferSetAttachment( + pixbuf, kCVImageBufferMasteringDisplayColorVolumeKey, + obs_to_vt_masteringdisplay(hdr_nominal_peak_level), + kCVAttachmentMode_ShouldPropagate); + CVBufferSetAttachment( + pixbuf, kCVImageBufferContentLightLevelInfoKey, + obs_to_vt_contentlightlevelinfo(hdr_nominal_peak_level), + kCVAttachmentMode_ShouldPropagate); + } *buf = pixbuf; return true; @@ -887,6 +1189,18 @@ return obs_module_text("VTH264EncHW"); } else if (strcmp("Apple H.264 (SW)", type_data->disp_name) == 0) { return obs_module_text("VTH264EncSW"); +#ifdef ENABLE_HEVC + } else if (strcmp("Apple HEVC (HW)", type_data->disp_name) == 0) { + return obs_module_text("VTHEVCEncHW"); + } else if (strcmp("Apple HEVC (AVE)", type_data->disp_name) == 0) { + return obs_module_text("VTHEVCEncT2"); + } else if (strcmp("Apple HEVC (SW)", type_data->disp_name) == 0) { + return obs_module_text("VTHEVCEncSW"); +#endif + } else if (strncmp("AppleProResHW", type_data->disp_name, 13) == 0) { + return obs_module_text("VTProResEncHW"); + } else if (strncmp("Apple ProRes", type_data->disp_name, 12) == 0) { + return obs_module_text("VTProResEncSW"); } return type_data->disp_name; } @@ -900,6 +1214,7 @@ #define TEXT_PROFILE obs_module_text("Profile") #define TEXT_BFRAMES obs_module_text("UseBFrames") #define TEXT_RATE_CONTROL obs_module_text("RateControl") +#define TEXT_PRORES_CODEC obs_module_text("ProResCodec") static bool rate_control_limit_bitrate_modified(obs_properties_t *ppts, obs_property_t *p, @@ -936,7 +1251,7 @@ return true; } -static obs_properties_t *vt_properties(void *unused, void *data) +static obs_properties_t *vt_properties_h26x(void *unused, void *data) { UNUSED_PARAMETER(unused); struct vt_encoder_type_data *type_data = data; @@ -992,15 +1307,85 @@ p = obs_properties_add_list(props, "profile", TEXT_PROFILE, OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_STRING); - obs_property_list_add_string(p, "baseline", "baseline"); - obs_property_list_add_string(p, "main", "main"); - obs_property_list_add_string(p, "high", "high"); + + if (type_data->codec_type == kCMVideoCodecType_H264) { + obs_property_list_add_string(p, "baseline", "baseline"); + obs_property_list_add_string(p, "main", "main"); + obs_property_list_add_string(p, "high", "high"); +#ifdef ENABLE_HEVC + } else if (type_data->codec_type == kCMVideoCodecType_HEVC) { + obs_property_list_add_string(p, "main", "main"); + obs_property_list_add_string(p, "main10", "main10"); + if (__builtin_available(macOS 12.3, *)) { + obs_property_list_add_string(p, "main 4:2:2 10", + "main42210"); + } +#endif + } obs_properties_add_bool(props, "bframes", TEXT_BFRAMES); return props; } +static obs_properties_t *vt_properties_prores(void *unused, void *data) +{ + UNUSED_PARAMETER(unused); + struct vt_encoder_type_data *type_data = data; + + obs_properties_t *props = obs_properties_create(); + obs_property_t *p; + + p = obs_properties_add_list(props, "codec_type", TEXT_PRORES_CODEC, + OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT); + + uint32_t codec_availability_flags = 0; + + size_t size = 0; + struct vt_prores_encoder_data *encoder_list = NULL; + if (type_data->hardware_accelerated) { + size = vt_prores_hardware_encoder_list.num; + encoder_list = vt_prores_hardware_encoder_list.array; + } else { + size = vt_prores_software_encoder_list.num; + encoder_list = vt_prores_software_encoder_list.array; + } + + for (size_t i = 0; i < size; ++i) { + + switch (encoder_listi.codec_type) { + case kCMVideoCodecType_AppleProRes422Proxy: + codec_availability_flags |= (1 << 0); + break; + case kCMVideoCodecType_AppleProRes422LT: + codec_availability_flags |= (1 << 1); + break; + case kCMVideoCodecType_AppleProRes422: + codec_availability_flags |= (1 << 2); + break; + case kCMVideoCodecType_AppleProRes422HQ: + codec_availability_flags |= (1 << 3); + break; + } + } + + if (codec_availability_flags & (1 << 0)) + obs_property_list_add_int( + p, obs_module_text("ProRes422Proxy"), + kCMVideoCodecType_AppleProRes422Proxy); + if (codec_availability_flags & (1 << 1)) + obs_property_list_add_int(p, obs_module_text("ProRes422LT"), + kCMVideoCodecType_AppleProRes422LT); + if (codec_availability_flags & (1 << 2)) + obs_property_list_add_int(p, obs_module_text("ProRes422"), + kCMVideoCodecType_AppleProRes422); + if (codec_availability_flags & (1 << 3)) + obs_property_list_add_int(p, obs_module_text("ProRes422HQ"), + kCMVideoCodecType_AppleProRes422HQ); + + return props; +} + static void vt_defaults(obs_data_t *settings, void *data) { struct vt_encoder_type_data *type_data = data; @@ -1020,7 +1405,12 @@ obs_data_set_default_int(settings, "max_bitrate", 2500); obs_data_set_default_double(settings, "max_bitrate_window", 1.5f); obs_data_set_default_int(settings, "keyint_sec", 0); - obs_data_set_default_string(settings, "profile", "main"); + obs_data_set_default_string( + settings, "profile", + type_data->codec_type == kCMVideoCodecType_H264 ? "high" + : "main"); + obs_data_set_default_int(settings, "codec_type", + kCMVideoCodecType_AppleProRes422); obs_data_set_default_bool(settings, "bframes", true); } @@ -1033,6 +1423,58 @@ bfree(type_data); } +static inline void +vt_add_prores_encoder_data_to_list(CFDictionaryRef encoder_dict, + FourCharCode codec_type) +{ + struct vt_prores_encoder_data *encoder_data = NULL; + + CFBooleanRef hardware_accelerated = CFDictionaryGetValue( + encoder_dict, kVTVideoEncoderList_IsHardwareAccelerated); + if (hardware_accelerated == kCFBooleanTrue) + encoder_data = + da_push_back_new(vt_prores_hardware_encoder_list); + else + encoder_data = + da_push_back_new(vt_prores_software_encoder_list); + + encoder_data->encoder_id = CFDictionaryGetValue( + encoder_dict, kVTVideoEncoderList_EncoderID); + + encoder_data->codec_type = codec_type; +} + +static CFComparisonResult +compare_encoder_list(const void *left_val, const void *right_val, void *unused) +{ + UNUSED_PARAMETER(unused); + + CFDictionaryRef left = (CFDictionaryRef)left_val; + CFDictionaryRef right = (CFDictionaryRef)right_val; + + CFNumberRef left_codec_num = + CFDictionaryGetValue(left, kVTVideoEncoderList_CodecType); + CFNumberRef right_codec_num = + CFDictionaryGetValue(right, kVTVideoEncoderList_CodecType); + CFComparisonResult result = + CFNumberCompare(left_codec_num, right_codec_num, NULL); + + if (result != kCFCompareEqualTo) + return result; + + CFBooleanRef left_hardware_accel = CFDictionaryGetValue( + left, kVTVideoEncoderList_IsHardwareAccelerated); + CFBooleanRef right_hardware_accel = CFDictionaryGetValue( + right, kVTVideoEncoderList_IsHardwareAccelerated); + + if (left_hardware_accel == right_hardware_accel) + return kCFCompareEqualTo; + else if (left_hardware_accel == kCFBooleanTrue) + return kCFCompareGreaterThan; + else + return kCFCompareLessThan; +} + OBS_DECLARE_MODULE() OBS_MODULE_USE_DEFAULT_LOCALE("mac-videotoolbox", "en-US") @@ -1040,39 +1482,80 @@ { struct obs_encoder_info info = { .type = OBS_ENCODER_VIDEO, - .codec = "h264", .get_name = vt_getname, .create = vt_create, .destroy = vt_destroy, .encode = vt_encode, .update = vt_update, - .get_properties2 = vt_properties, .get_defaults2 = vt_defaults, .get_extra_data = vt_extra_data, .free_type_data = vt_free_type_data, .caps = OBS_ENCODER_CAP_DYN_BITRATE, }; - CFArrayRef encoder_list; - VTCopyVideoEncoderList(NULL, &encoder_list); - CFIndex size = CFArrayGetCount(encoder_list); + da_init(vt_prores_hardware_encoder_list); + da_init(vt_prores_software_encoder_list); + + CFArrayRef encoder_list_const; + VTCopyVideoEncoderList(NULL, &encoder_list_const); + CFIndex size = CFArrayGetCount(encoder_list_const); + + CFMutableArrayRef encoder_list = CFArrayCreateMutableCopy( + kCFAllocatorDefault, size, encoder_list_const); + CFRelease(encoder_list_const); + + CFArraySortValues(encoder_list, CFRangeMake(0, size), + &compare_encoder_list, NULL); for (CFIndex i = 0; i < size; i++) { CFDictionaryRef encoder_dict = CFArrayGetValueAtIndex(encoder_list, i); -#define VT_DICTSTR(key, name) \ - CFStringRef name##_ref = CFDictionaryGetValue(encoder_dict, key); \ - CFIndex name##_len = CFStringGetLength(name##_ref); \ - char *name = bzalloc(name##_len + 1); \ +#define VT_DICTSTR(key, name) \ + CFStringRef name##_ref = CFDictionaryGetValue(encoder_dict, key); \ + CFIndex name##_len = \ + CFStringGetMaximumSizeOfFileSystemRepresentation(name##_ref); \ + char *name = bzalloc(name##_len + 1); \ CFStringGetFileSystemRepresentation(name##_ref, name, name##_len); - VT_DICTSTR(kVTVideoEncoderList_CodecName, codec_name); - if (strcmp("H.264", codec_name) != 0) { - bfree(codec_name); + CMVideoCodecType codec_type = 0; + { + CFNumberRef codec_type_num = CFDictionaryGetValue( + encoder_dict, kVTVideoEncoderList_CodecType); + CFNumberGetValue(codec_type_num, kCFNumberSInt32Type, + &codec_type); + } + + switch (codec_type) { + case kCMVideoCodecType_H264: + info.get_properties2 = vt_properties_h26x; + info.codec = "h264"; + break; +#ifdef ENABLE_HEVC + case kCMVideoCodecType_HEVC: + info.get_properties2 = vt_properties_h26x; + info.codec = "hevc"; + break; +#endif + // 422 is used as a marker for all ProRes types, + // since the type is stored as a profile + case kCMVideoCodecType_AppleProRes422: + info.get_properties2 = vt_properties_prores; + info.codec = "prores"; + vt_add_prores_encoder_data_to_list(encoder_dict, + codec_type); + break; + + case kCMVideoCodecType_AppleProRes422Proxy: + case kCMVideoCodecType_AppleProRes422LT: + case kCMVideoCodecType_AppleProRes422HQ: + vt_add_prores_encoder_data_to_list(encoder_dict, + codec_type); + continue; + + default: continue; } - bfree(codec_name); VT_DICTSTR(kVTVideoEncoderList_EncoderID, id); VT_DICTSTR(kVTVideoEncoderList_DisplayName, disp_name); @@ -1089,6 +1572,7 @@ bzalloc(sizeof(struct vt_encoder_type_data)); type_data->disp_name = disp_name; type_data->id = id; + type_data->codec_type = codec_type; type_data->hardware_accelerated = hardware_accelerated; info.type_data = type_data; @@ -1102,3 +1586,9 @@ return true; } + +void obs_module_unload(void) +{ + da_free(vt_prores_hardware_encoder_list); + da_free(vt_prores_software_encoder_list); +}
View file
obs-studio-28.1.2.tar.xz/plugins/mac-virtualcam/src/dal-plugin/OBSDALMachClient.mm -> obs-studio-29.0.0.tar.xz/plugins/mac-virtualcam/src/dal-plugin/OBSDALMachClient.mm
Changed
@@ -10,7 +10,6 @@ #import "Logging.h" @interface OBSDALMachClient () <NSPortDelegate> { - uint32_t _seed; NSPort *_receivePort; } @end @@ -123,11 +122,20 @@ return; } - IOSurfaceLock(surface, 0, &_seed); + /* + * IOSurfaceLocks are only necessary on non Apple Silicon devices, as those have + * unified memory. On Intel machines, the lock ensures that the IOSurface is copied back + * from GPU memory to CPU memory so we can process the pixel buffer. + */ +#ifndef __aarch64__ + IOSurfaceLock(surface, kIOSurfaceLockReadOnly, NULL); +#endif CVPixelBufferRef frame; CVPixelBufferCreateWithIOSurface(kCFAllocatorDefault, surface, NULL, &frame); - IOSurfaceUnlock(surface, 0, &_seed); +#ifndef __aarch64__ + IOSurfaceUnlock(surface, kIOSurfaceLockReadOnly, NULL); +#endif CFRelease(surface); uint64_t timestamp;
View file
obs-studio-28.1.2.tar.xz/plugins/mac-virtualcam/src/obs-plugin/OBSDALMachServer.mm -> obs-studio-29.0.0.tar.xz/plugins/mac-virtualcam/src/obs-plugin/OBSDALMachServer.mm
Changed
@@ -15,7 +15,6 @@ @property NSPort *port; @property NSMutableSet *clientPorts; @property NSRunLoop *runLoop; -@property uint32_t seed; @end @implementation OBSDALMachServer @@ -156,7 +155,6 @@ return; } - IOSurfaceLock(surface, 0, &_seed); mach_port_t framePort = IOSurfaceCreateMachPort(surface); if (!framePort) { @@ -176,7 +174,6 @@ ; mach_port_deallocate(mach_task_self(), framePort); - IOSurfaceUnlock(surface, 0, &_seed); } }
View file
obs-studio-28.1.2.tar.xz/plugins/mac-virtualcam/src/obs-plugin/plugin-main.mm -> obs-studio-29.0.0.tar.xz/plugins/mac-virtualcam/src/obs-plugin/plugin-main.mm
Changed
@@ -84,11 +84,9 @@ copyPluginCmd; NSDictionary *errorDict; - NSAppleEventDescriptor *returnDescriptor = NULL; NSAppleScript *scriptObject = NSAppleScript alloc initWithSource:copyCmd; - returnDescriptor = - scriptObject executeAndReturnError:&errorDict; + scriptObject executeAndReturnError:&errorDict; if (errorDict != nil) { const char *errorMessage = errorDict objectForKey:@"NSAppleScriptErrorMessage"
View file
obs-studio-28.1.2.tar.xz/plugins/obs-browser/browser-version.h -> obs-studio-29.0.0.tar.xz/plugins/obs-browser/browser-version.h
Changed
@@ -1,8 +1,8 @@ #pragma once #define OBS_BROWSER_VERSION_MAJOR 2 -#define OBS_BROWSER_VERSION_MINOR 18 -#define OBS_BROWSER_VERSION_PATCH 7 +#define OBS_BROWSER_VERSION_MINOR 19 +#define OBS_BROWSER_VERSION_PATCH 0 #ifndef MAKE_SEMANTIC_VERSION #define MAKE_SEMANTIC_VERSION(major, minor, patch) \
View file
obs-studio-28.1.2.tar.xz/plugins/obs-browser/data/locale/en-US.ini -> obs-studio-29.0.0.tar.xz/plugins/obs-browser/data/locale/en-US.ini
Changed
@@ -11,6 +11,8 @@ BrowserSource="Browser" CustomFrameRate="Use custom frame rate" RerouteAudio="Control audio via OBS" +Inspect="Inspect" +DevTools="Inspect Browser Dock '%1'" WebpageControlLevel="Page permissions" WebpageControlLevel.Level.None="No access to OBS" WebpageControlLevel.Level.ReadObs="Read access to OBS status information"
View file
obs-studio-28.1.2.tar.xz/plugins/obs-browser/obs-browser-plugin.cpp -> obs-studio-29.0.0.tar.xz/plugins/obs-browser/obs-browser-plugin.cpp
Changed
@@ -306,8 +306,14 @@ CefMainArgs args(cmdline_args.argc, cmdline_args.argv); #endif + BPtr<char> conf_path = obs_module_config_path(""); + os_mkdir(conf_path); + CefSettings settings; settings.log_severity = LOGSEVERITY_DISABLE; + BPtr<char> log_path = obs_module_config_path("debug.log"); + BPtr<char> log_path_abs = os_get_abs_path_ptr(log_path); + CefString(&settings.log_file) = log_path_abs; settings.windowless_rendering_enabled = true; settings.no_sandbox = true; @@ -358,8 +364,6 @@ accepted_languages = "en-US,en"; } - BPtr<char> conf_path = obs_module_config_path(""); - os_mkdir(conf_path); BPtr<char> conf_path_abs = os_get_abs_path_ptr(conf_path); CefString(&settings.locale) = obs_get_locale(); CefString(&settings.accept_language_list) = accepted_languages;
View file
obs-studio-28.1.2.tar.xz/plugins/obs-browser/panel/browser-panel-client.cpp -> obs-studio-29.0.0.tar.xz/plugins/obs-browser/panel/browser-panel-client.cpp
Changed
@@ -19,6 +19,9 @@ #include <X11/Xlib.h> #endif +#define MENU_ITEM_DEVTOOLS MENU_ID_CUSTOM_FIRST +#define MENU_ITEM_MUTE MENU_ID_CUSTOM_FIRST + 1 + /* CefClient */ CefRefPtr<CefLoadHandler> QCefBrowserClient::GetLoadHandler() { @@ -70,6 +73,9 @@ QMetaObject::invokeMethod(widget, "titleChanged", Q_ARG(QString, qt_title)); } else { /* handle popup title */ + if (title.compare("DevTools") == 0) + return; + CefWindowHandle handl = browser->GetHost()->GetWindowHandle(); #ifdef _WIN32 std::wstring str_title = title; @@ -228,7 +234,7 @@ } } -void QCefBrowserClient::OnBeforeContextMenu(CefRefPtr<CefBrowser>, +void QCefBrowserClient::OnBeforeContextMenu(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame>, CefRefPtr<CefContextMenuParams>, CefRefPtr<CefMenuModel> model) @@ -243,6 +249,15 @@ if (model->IsVisible(MENU_ID_PRINT)) { model->Remove(MENU_ID_PRINT); } + if (model->IsVisible(MENU_ID_VIEW_SOURCE)) { + model->Remove(MENU_ID_VIEW_SOURCE); + } + model->AddSeparator(); + model->InsertItemAt(model->GetCount(), MENU_ITEM_DEVTOOLS, + obs_module_text("Inspect")); + model->InsertCheckItemAt(model->GetCount(), MENU_ITEM_MUTE, + QObject::tr("Mute").toUtf8().constData()); + model->SetChecked(MENU_ITEM_MUTE, browser->GetHost()->IsAudioMuted()); } #if defined(_WIN32) @@ -251,12 +266,13 @@ CefRefPtr<CefContextMenuParams>, CefRefPtr<CefMenuModel> model, CefRefPtr<CefRunContextMenuCallback> callback) { - std::vector<std::tuple<std::string, int, bool, int>> menu_items; + std::vector<std::tuple<std::string, int, bool, int, bool>> menu_items; menu_items.reserve(model->GetCount()); for (int i = 0; i < model->GetCount(); i++) { menu_items.push_back( {model->GetLabelAt(i), model->GetCommandIdAt(i), - model->IsEnabledAt(i), model->GetTypeAt(i)}); + model->IsEnabledAt(i), model->GetTypeAt(i), + model->IsCheckedAt(i)}); } QMetaObject::invokeMethod( @@ -267,16 +283,22 @@ int command_id; bool enabled; int type_id; + bool check; - for (const std::tuple<std::string, int, bool, int> + for (const std::tuple<std::string, int, bool, int, bool> &menu_item : menu_items) { - std::tie(name, command_id, enabled, type_id) = - menu_item; + std::tie(name, command_id, enabled, type_id, + check) = menu_item; switch (type_id) { + case MENUITEMTYPE_CHECK: case MENUITEMTYPE_COMMAND: { QAction *item = new QAction(name.c_str()); item->setEnabled(enabled); + if (type_id == MENUITEMTYPE_CHECK) { + item->setCheckable(true); + item->setChecked(check); + } item->setProperty("cmd_id", command_id); contextMenu.addAction(item); } break; @@ -299,6 +321,41 @@ } #endif +bool QCefBrowserClient::OnContextMenuCommand( + CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame>, + CefRefPtr<CefContextMenuParams> params, int command_id, + CefContextMenuHandler::EventFlags) +{ + if (command_id < MENU_ID_CUSTOM_FIRST) + return false; + CefRefPtr<CefBrowserHost> host = browser->GetHost(); + CefWindowInfo windowInfo; + QPoint pos; + QString title; + switch (command_id) { + case MENU_ITEM_DEVTOOLS: +#if defined(_WIN32) + title = QString(obs_module_text("DevTools")) + .arg(widget->parentWidget()->windowTitle()); + windowInfo.SetAsPopup(host->GetWindowHandle(), + title.toUtf8().constData()); +#endif + pos = widget->mapToGlobal(QPoint(0, 0)); + windowInfo.bounds.x = pos.x(); + windowInfo.bounds.y = pos.y() + 30; + windowInfo.bounds.width = 900; + windowInfo.bounds.height = 700; + host->ShowDevTools( + windowInfo, host->GetClient(), CefBrowserSettings(), + {params.get()->GetXCoord(), params.get()->GetYCoord()}); + return true; + case MENU_ITEM_MUTE: + host->SetAudioMuted(!host->IsAudioMuted()); + return true; + } + return false; +} + void QCefBrowserClient::OnLoadEnd(CefRefPtr<CefBrowser>, CefRefPtr<CefFrame> frame, int) {
View file
obs-studio-28.1.2.tar.xz/plugins/obs-browser/panel/browser-panel-client.hpp -> obs-studio-29.0.0.tar.xz/plugins/obs-browser/panel/browser-panel-client.hpp
Changed
@@ -89,6 +89,11 @@ CefRefPtr<CefRunContextMenuCallback> callback) override; #endif + virtual bool OnContextMenuCommand( + CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, + CefRefPtr<CefContextMenuParams> params, int command_id, + CefContextMenuHandler::EventFlags event_flags) override; + /* CefLoadHandler */ virtual void OnLoadEnd(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame,
View file
obs-studio-28.1.2.tar.xz/plugins/obs-ffmpeg/CMakeLists.txt -> obs-studio-29.0.0.tar.xz/plugins/obs-ffmpeg/CMakeLists.txt
Changed
@@ -119,9 +119,11 @@ obs-ffmpeg.rc) elseif(OS_POSIX AND NOT OS_MACOS) + find_package(Libva REQUIRED) find_package(Libpci REQUIRED) - target_sources(obs-ffmpeg PRIVATE obs-ffmpeg-vaapi.c) - target_link_libraries(obs-ffmpeg PRIVATE LIBPCI::LIBPCI) + target_sources(obs-ffmpeg PRIVATE obs-ffmpeg-vaapi.c vaapi-utils.c + vaapi-utils.h) + target_link_libraries(obs-ffmpeg PRIVATE Libva::va LIBPCI::LIBPCI) endif() setup_plugin_target(obs-ffmpeg)
View file
obs-studio-28.1.2.tar.xz/plugins/obs-ffmpeg/data/locale/en-US.ini -> obs-studio-29.0.0.tar.xz/plugins/obs-ffmpeg/data/locale/en-US.ini
Changed
@@ -14,7 +14,7 @@ Level="Level" AMFOpts="AMF/FFmpeg Options" -AMFOpts.ToolTip="Use to specify custom AMF or FFmpeg options. For example, \"level=5.2 profile=main BPicturesPattern=3\"" +AMFOpts.ToolTip="Use to specify custom AMF or FFmpeg options. For example, \"level=5.2 profile=main\". Check the AMF encoder docs for more details." BFrames="Max B-frames" @@ -48,6 +48,7 @@ AMF.Preset.speed="Speed" AMF.Preset.balanced="Balanced" AMF.Preset.quality="Quality" +AMF.Preset.highQuality="High Quality" FFmpegSource="Media Source" LocalFile="Local File"
View file
obs-studio-28.1.2.tar.xz/plugins/obs-ffmpeg/external/AMF/include/components/Component.h -> obs-studio-29.0.0.tar.xz/plugins/obs-ffmpeg/external/AMF/include/components/Component.h
Changed
@@ -414,6 +414,7 @@ AMF_STREAM_CODEC_ID_VP9 = 11, // AMFVideoDecoderHW_VP9 AMF_STREAM_CODEC_ID_VP9_10BIT = 12, // AMFVideoDecoderHW_VP9_10BIT AMF_STREAM_CODEC_ID_AV1 = 13, // AMFVideoDecoderHW_AV1 + AMF_STREAM_CODEC_ID_AV1_12BIT = 14, // AMFVideoDecoderHW_AV1_12BIT } AMF_STREAM_CODEC_ID_ENUM; // common stream properties
View file
obs-studio-28.1.2.tar.xz/plugins/obs-ffmpeg/external/AMF/include/components/CursorCapture.h -> obs-studio-29.0.0.tar.xz/plugins/obs-ffmpeg/external/AMF/include/components/CursorCapture.h
Changed
@@ -43,6 +43,7 @@ class AMFCursorCapture : public AMFInterface { public: + AMF_DECLARE_IID(0x166efa1a, 0x19b8, 0x42f2, 0x86, 0x0f, 0x56, 0x69, 0xca, 0x7a, 0x85, 0x4c) virtual AMF_RESULT AMF_STD_CALL AcquireCursor(amf::AMFSurface** pSurface) = 0; virtual AMF_RESULT AMF_STD_CALL Reset() = 0; };
View file
obs-studio-28.1.2.tar.xz/plugins/obs-ffmpeg/external/AMF/include/components/FFMPEGFileMuxer.h -> obs-studio-29.0.0.tar.xz/plugins/obs-ffmpeg/external/AMF/include/components/FFMPEGFileMuxer.h
Changed
@@ -49,5 +49,6 @@ #define FFMPEG_MUXER_ENABLE_AUDIO L"EnableAudio" // bool (default = false) #define FFMPEG_MUXER_CURRENT_TIME_INTERFACE L"CurrentTimeInterface" #define FFMPEG_MUXER_VIDEO_ROTATION L"VideoRotation" // amf_int64 (0, 90, 180, 270, default = 0) +#define FFMPEG_MUXER_USAGE_IS_TRIM L"UsageIsTrim" // bool (default = false) #endif //#ifndef AMF_FileMuxerFFMPEG_h
View file
obs-studio-28.1.2.tar.xz/plugins/obs-ffmpeg/external/AMF/include/components/HQScaler.h -> obs-studio-29.0.0.tar.xz/plugins/obs-ffmpeg/external/AMF/include/components/HQScaler.h
Changed
@@ -44,6 +44,8 @@ AMF_HQ_SCALER_ALGORITHM_BILINEAR = 0, AMF_HQ_SCALER_ALGORITHM_BICUBIC = 1, AMF_HQ_SCALER_ALGORITHM_FSR = 2, + AMF_HQ_SCALER_ALGORITHM_POINT = 3, + AMF_HQ_SCALER_ALGORITHM_FSR1_1 = 4, }; @@ -60,5 +62,6 @@ #define AMF_HQ_SCALER_FILL_COLOR L"FillColor" // AMFColor #define AMF_HQ_SCALER_FROM_SRGB L"FromSRGB" // bool (default=true) Convert to SRGB. +#define AMF_HQ_SCALER_SHARPNESS L"HQScalerSharpness" // Float in the range of 0.0, 2.0 #endif //#ifndef AMFHQScaler_h
View file
obs-studio-28.1.2.tar.xz/plugins/obs-ffmpeg/external/AMF/include/components/PreAnalysis.h -> obs-studio-29.0.0.tar.xz/plugins/obs-ffmpeg/external/AMF/include/components/PreAnalysis.h
Changed
@@ -1,4 +1,4 @@ -// +// // Notice Regarding Standards. AMD does not provide a license or sublicense to // any Intellectual Property Rights relating to any standards, including but not // limited to any audio and/or video codec technologies such as MPEG-2, MPEG-4; @@ -6,9 +6,9 @@ // (collectively, the "Media Technologies"). For clarity, you will pay any // royalties due for such third party technologies, which may include the Media // Technologies that are owed as a result of AMD providing the Software to you. -// -// MIT license -// +// +// MIT license +// // Copyright (c) 2019 Advanced Micro Devices, Inc. All rights reserved. // // Permission is hereby granted, free of charge, to any person obtaining a copy @@ -48,7 +48,7 @@ enum AMF_PA_STATIC_SCENE_DETECTION_SENSITIVITY_ENUM -{ +{ AMF_PA_STATIC_SCENE_DETECTION_SENSITIVITY_LOW = 0, AMF_PA_STATIC_SCENE_DETECTION_SENSITIVITY_MEDIUM = 1, AMF_PA_STATIC_SCENE_DETECTION_SENSITIVITY_HIGH = 2 @@ -69,6 +69,26 @@ AMF_PA_CAQ_STRENGTH_HIGH = 2 }; +// Perceptual adaptive quantization mode +enum AMF_PA_PAQ_MODE_ENUM +{ + AMF_PA_PAQ_MODE_NONE = 0, + AMF_PA_PAQ_MODE_CAQ = 1 +}; + +// Temporal adaptive quantization mode +enum AMF_PA_TAQ_MODE_ENUM +{ + AMF_PA_TAQ_MODE_NONE = 0, + AMF_PA_TAQ_MODE_1 = 1, + AMF_PA_TAQ_MODE_2 = 2 +}; + +enum AMF_PA_HIGH_MOTION_QUALITY_BOOST_MODE_ENUM +{ + AMF_PA_HIGH_MOTION_QUALITY_BOOST_MODE_NONE = 0, //default + AMF_PA_HIGH_MOTION_QUALITY_BOOST_MODE_AUTO = 1 +}; // PA object properties @@ -77,17 +97,19 @@ #define AMF_PA_SCENE_CHANGE_DETECTION_ENABLE L"PASceneChangeDetectionEnable" // bool (default : True) - Enable Scene Change Detection GPU algorithm #define AMF_PA_SCENE_CHANGE_DETECTION_SENSITIVITY L"PASceneChangeDetectionSensitivity" // AMF_PA_SCENE_CHANGE_DETECTION_SENSITIVITY_ENUM (default : Medium) - Scene Change Detection Sensitivity -#define AMF_PA_STATIC_SCENE_DETECTION_ENABLE L"PAStaticSceneDetectionEnable" // bool (default : True) - Enable Skip Detection GPU algorithm +#define AMF_PA_STATIC_SCENE_DETECTION_ENABLE L"PAStaticSceneDetectionEnable" // bool (default : False) - Enable Skip Detection GPU algorithm #define AMF_PA_STATIC_SCENE_DETECTION_SENSITIVITY L"PAStaticSceneDetectionSensitivity" // AMF_PA_STATIC_SCENE_DETECTION_SENSITIVITY_ENUM (default : High) - Allowable absolute difference between pixels (sample counts) #define AMF_PA_FRAME_SAD_ENABLE L"PAFrameSadEnable" // bool (default : True) - Enable Frame SAD algorithm #define AMF_PA_ACTIVITY_TYPE L"PAActivityType" // AMF_PA_ACTIVITY_TYPE_ENUM (default : Calculate on Y) - Block activity calculation mode -#define AMF_PA_LTR_ENABLE L"PALongTermReferenceEnable" // bool (default : True) - Enable Automatic Long Term Reference frame management - - +#define AMF_PA_LTR_ENABLE L"PALongTermReferenceEnable" // bool (default : False) - Enable Automatic Long Term Reference frame management +#define AMF_PA_LOOKAHEAD_BUFFER_DEPTH L"PALookAheadBufferDepth" // amf_uint64 (default : 0) Values: 0, MAX_LOOKAHEAD_DEPTH - PA lookahead buffer size +#define AMF_PA_PAQ_MODE L"PAPerceptualAQMode" // AMF_PA_PAQ_MODE_ENUM (default : AMF_PA_PAQ_MODE_NONE) - Perceptual AQ mode +#define AMF_PA_TAQ_MODE L"PATemporalAQMode" // AMF_PA_TAQ_MODE_ENUM (default: AMF_PA_TAQ_MODE_NONE) - Temporal AQ mode +#define AMF_PA_HIGH_MOTION_QUALITY_BOOST_MODE L"PAHighMotionQualityBoostMode" // AMF_PA_HIGH_MOTION_QUALITY_BOOST_MODE_ENUM (default: None) - High motion quality boost mode /////////////////////////////////////////// -// the following properties are available -// only through the Encoder - trying to +// the following properties are available +// only through the Encoder - trying to // access/set them when PA is standalone // will fail @@ -107,4 +129,5 @@ #define AMF_PA_SCENE_CHANGE_DETECT L"PASceneChangeDetect" // bool - True/False - available if AMF_PA_SCENE_CHANGE_DETECTION_ENABLE was set to True #define AMF_PA_STATIC_SCENE_DETECT L"PAStaticSceneDetect" // bool - True/False - available if AMF_PA_STATIC_SCENE_DETECTION_ENABLE was set to True + #endif //#ifndef AMFPreAnalysis_h
View file
obs-studio-29.0.0.tar.xz/plugins/obs-ffmpeg/external/AMF/include/components/VQEnhancer.h
Added
@@ -0,0 +1,47 @@ +// +// Notice Regarding Standards. AMD does not provide a license or sublicense to +// any Intellectual Property Rights relating to any standards, including but not +// limited to any audio and/or video codec technologies such as MPEG-2, MPEG-4; +// AVC/H.264; HEVC/H.265; AAC decode/FFMPEG; AAC encode/FFMPEG; VC-1; and MP3 +// (collectively, the "Media Technologies"). For clarity, you will pay any +// royalties due for such third party technologies, which may include the Media +// Technologies that are owed as a result of AMD providing the Software to you. +// +// MIT license +// +// Copyright (c) 2021 Advanced Micro Devices, Inc. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +#ifndef AMFVQEnhancer_h +#define AMFVQEnhancer_h + +#pragma once + +#define VE_FCR_DEFAULT_ATTENUATION 0.1 + +#define AMFVQEnhancer L"AMFVQEnhancer" + +#define AMF_VIDEO_ENHANCER_ENGINE_TYPE L"AMF_VIDEI_ENHANCER_ENGINE_TYPE" // AMF_MEMORY_TYPE (DX11, DX12, OPENCL, VULKAN default : DX11)" - determines how the object is initialized and what kernels to use +#define AMF_VIDEO_ENHANCER_OUTPUT_SIZE L"AMF_VIDEO_ENHANCER_OUTPUT_SIZE" // AMFSize +#define AMF_VE_FCR_ATTENUATION L"AMF_VE_FCR_ATTENUATION" // Float in the range of 0.02, 0.4, default : 0.1 +#define AMF_VE_FCR_RADIUS L"AMF_VE_FCR_RADIUS" // int in the range of 1, 4 + +#endif //#ifndef AMFVQEnhancer_h
View file
obs-studio-28.1.2.tar.xz/plugins/obs-ffmpeg/external/AMF/include/components/VideoDecoderUVD.h -> obs-studio-29.0.0.tar.xz/plugins/obs-ffmpeg/external/AMF/include/components/VideoDecoderUVD.h
Changed
@@ -53,6 +53,7 @@ #define AMFVideoDecoderHW_VP9 L"AMFVideoDecoderHW_VP9" #define AMFVideoDecoderHW_VP9_10BIT L"AMFVideoDecoderHW_VP9_10BIT" #define AMFVideoDecoderHW_AV1 L"AMFVideoDecoderHW_AV1" +#define AMFVideoDecoderHW_AV1_12BIT L"AMFVideoDecoderHW_AV1_12BIT" enum AMF_VIDEO_DECODER_MODE_ENUM { @@ -108,6 +109,7 @@ #define AMF_VIDEO_DECODER_OUTPUT_COLOR_PRIMARIES L"OutputColorPrimaries" // amf_int64(AMF_COLOR_PRIMARIES_ENUM); default = AMF_COLOR_PRIMARIES_UNDEFINED, ISO/IEC 23001-8_2013 7.1 See ColorSpace.h for enum #define AMF_VIDEO_DECODER_OUTPUT_HDR_METADATA L"OutHDRMetadata" // AMFBuffer containing AMFHDRMetadata; default NULL +#define AMF_VIDEO_DECODER_LOW_LATENCY L"LowLatencyDecode" // amf_bool; default = false; true = low latency decode, false = regular decode #if defined(__ANDROID__) #define AMF_VIDEO_DECODER_NATIVEWINDOW L"AndroidNativeWindow" // amf_int64; default = 0; pointer to native window @@ -118,5 +120,4 @@ #define AMF_VIDEO_DECODER_NATIVEWINDOW L"AppleNativeWindow" // amf_int64; default = 0; pointer to native window #endif //__APPLE__ - #endif //#ifndef AMF_VideoDecoderUVD_h
View file
obs-studio-29.0.0.tar.xz/plugins/obs-ffmpeg/external/AMF/include/components/VideoEncoderAV1.h
Added
@@ -0,0 +1,292 @@ +// +// Copyright (c) 2021-2022 Advanced Micro Devices, Inc. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +//------------------------------------------------------------------------------------------------- +// VideoEncoderHW_AV1 interface declaration +//------------------------------------------------------------------------------------------------- + +#ifndef AMF_VideoEncoderAV1_h +#define AMF_VideoEncoderAV1_h +#pragma once + +#include "Component.h" +#include "ColorSpace.h" +#include "PreAnalysis.h" + +#define AMFVideoEncoder_AV1 L"AMFVideoEncoderHW_AV1" + +enum AMF_VIDEO_ENCODER_AV1_ENCODING_LATENCY_MODE_ENUM +{ + AMF_VIDEO_ENCODER_AV1_ENCODING_LATENCY_MODE_NONE = 0, // No encoding latency requirement. Encoder will balance encoding time and power consumption. + AMF_VIDEO_ENCODER_AV1_ENCODING_LATENCY_MODE_POWER_SAVING_REAL_TIME = 1, // Try the best to finish encoding a frame within 1/framerate sec. This mode may cause more power consumption + AMF_VIDEO_ENCODER_AV1_ENCODING_LATENCY_MODE_REAL_TIME = 2, // Try the best to finish encoding a frame within 1/(2 x framerate) sec. This mode will cause more power consumption than POWER_SAVING_REAL_TIME + AMF_VIDEO_ENCODER_AV1_ENCODING_LATENCY_MODE_LOWEST_LATENCY = 3 // Encoding as fast as possible. This mode causes highest power consumption. +}; + +enum AMF_VIDEO_ENCODER_AV1_USAGE_ENUM +{ + AMF_VIDEO_ENCODER_AV1_USAGE_TRANSCODING = 0, + AMF_VIDEO_ENCODER_AV1_USAGE_LOW_LATENCY = 1 +}; + +enum AMF_VIDEO_ENCODER_AV1_PROFILE_ENUM +{ + AMF_VIDEO_ENCODER_AV1_PROFILE_MAIN = 1 +}; + +enum AMF_VIDEO_ENCODER_AV1_LEVEL_ENUM +{ + AMF_VIDEO_ENCODER_AV1_LEVEL_2_0 = 0, + AMF_VIDEO_ENCODER_AV1_LEVEL_2_1 = 1, + AMF_VIDEO_ENCODER_AV1_LEVEL_2_2 = 2, + AMF_VIDEO_ENCODER_AV1_LEVEL_2_3 = 3, + AMF_VIDEO_ENCODER_AV1_LEVEL_3_0 = 4, + AMF_VIDEO_ENCODER_AV1_LEVEL_3_1 = 5, + AMF_VIDEO_ENCODER_AV1_LEVEL_3_2 = 6, + AMF_VIDEO_ENCODER_AV1_LEVEL_3_3 = 7, + AMF_VIDEO_ENCODER_AV1_LEVEL_4_0 = 8, + AMF_VIDEO_ENCODER_AV1_LEVEL_4_1 = 9, + AMF_VIDEO_ENCODER_AV1_LEVEL_4_2 = 10, + AMF_VIDEO_ENCODER_AV1_LEVEL_4_3 = 11, + AMF_VIDEO_ENCODER_AV1_LEVEL_5_0 = 12, + AMF_VIDEO_ENCODER_AV1_LEVEL_5_1 = 13, + AMF_VIDEO_ENCODER_AV1_LEVEL_5_2 = 14, + AMF_VIDEO_ENCODER_AV1_LEVEL_5_3 = 15, + AMF_VIDEO_ENCODER_AV1_LEVEL_6_0 = 16, + AMF_VIDEO_ENCODER_AV1_LEVEL_6_1 = 17, + AMF_VIDEO_ENCODER_AV1_LEVEL_6_2 = 18, + AMF_VIDEO_ENCODER_AV1_LEVEL_6_3 = 19, + AMF_VIDEO_ENCODER_AV1_LEVEL_7_0 = 20, + AMF_VIDEO_ENCODER_AV1_LEVEL_7_1 = 21, + AMF_VIDEO_ENCODER_AV1_LEVEL_7_2 = 22, + AMF_VIDEO_ENCODER_AV1_LEVEL_7_3 = 23 +}; + +enum AMF_VIDEO_ENCODER_AV1_RATE_CONTROL_METHOD_ENUM +{ + AMF_VIDEO_ENCODER_AV1_RATE_CONTROL_METHOD_UNKNOWN = -1, + AMF_VIDEO_ENCODER_AV1_RATE_CONTROL_METHOD_CONSTANT_QP = 0, + AMF_VIDEO_ENCODER_AV1_RATE_CONTROL_METHOD_LATENCY_CONSTRAINED_VBR = 1, + AMF_VIDEO_ENCODER_AV1_RATE_CONTROL_METHOD_PEAK_CONSTRAINED_VBR = 2, + AMF_VIDEO_ENCODER_AV1_RATE_CONTROL_METHOD_CBR = 3, + AMF_VIDEO_ENCODER_AV1_RATE_CONTROL_METHOD_QUALITY_VBR = 4, + AMF_VIDEO_ENCODER_AV1_RATE_CONTROL_METHOD_HIGH_QUALITY_VBR = 5, + AMF_VIDEO_ENCODER_AV1_RATE_CONTROL_METHOD_HIGH_QUALITY_CBR = 6 +}; + +enum AMF_VIDEO_ENCODER_AV1_ALIGNMENT_MODE_ENUM +{ + AMF_VIDEO_ENCODER_AV1_ALIGNMENT_MODE_64X16_ONLY = 1, + AMF_VIDEO_ENCODER_AV1_ALIGNMENT_MODE_64X16_1080P_CODED_1082 = 2, + AMF_VIDEO_ENCODER_AV1_ALIGNMENT_MODE_NO_RESTRICTIONS = 3 +}; + +enum AMF_VIDEO_ENCODER_AV1_FORCE_FRAME_TYPE_ENUM +{ + AMF_VIDEO_ENCODER_AV1_FORCE_FRAME_TYPE_NONE = 0, + AMF_VIDEO_ENCODER_AV1_FORCE_FRAME_TYPE_KEY = 1, + AMF_VIDEO_ENCODER_AV1_FORCE_FRAME_TYPE_INTRA_ONLY = 2, + AMF_VIDEO_ENCODER_AV1_FORCE_FRAME_TYPE_SWITCH = 3, + AMF_VIDEO_ENCODER_AV1_FORCE_FRAME_TYPE_SHOW_EXISTING = 4 +}; + +enum AMF_VIDEO_ENCODER_AV1_OUTPUT_FRAME_TYPE_ENUM +{ + AMF_VIDEO_ENCODER_AV1_OUTPUT_FRAME_TYPE_KEY = 0, + AMF_VIDEO_ENCODER_AV1_OUTPUT_FRAME_TYPE_INTRA_ONLY = 1, + AMF_VIDEO_ENCODER_AV1_OUTPUT_FRAME_TYPE_INTER = 2, + AMF_VIDEO_ENCODER_AV1_OUTPUT_FRAME_TYPE_SWITCH = 3, + AMF_VIDEO_ENCODER_AV1_OUTPUT_FRAME_TYPE_SHOW_EXISTING = 4 +}; + +enum AMF_VIDEO_ENCODER_AV1_QUALITY_PRESET_ENUM +{ + AMF_VIDEO_ENCODER_AV1_QUALITY_PRESET_HIGH_QUALITY = 0, + AMF_VIDEO_ENCODER_AV1_QUALITY_PRESET_QUALITY = 30, + AMF_VIDEO_ENCODER_AV1_QUALITY_PRESET_BALANCED = 70, + AMF_VIDEO_ENCODER_AV1_QUALITY_PRESET_SPEED = 100 +}; + +enum AMF_VIDEO_ENCODER_AV1_HEADER_INSERTION_MODE_ENUM +{ + AMF_VIDEO_ENCODER_AV1_HEADER_INSERTION_MODE_NONE = 0, + AMF_VIDEO_ENCODER_AV1_HEADER_INSERTION_MODE_GOP_ALIGNED = 1, + AMF_VIDEO_ENCODER_AV1_HEADER_INSERTION_MODE_KEY_FRAME_ALIGNED = 2 +}; + +enum AMF_VIDEO_ENCODER_AV1_SWITCH_FRAME_INSERTION_MODE_ENUM +{ + AMF_VIDEO_ENCODER_AV1_SWITCH_FRAME_INSERTION_MODE_NONE = 0, + AMF_VIDEO_ENCODER_AV1_SWITCH_FRAME_INSERTION_MODE_FIXED_INTERVAL = 1 +}; + +enum AMF_VIDEO_ENCODER_AV1_CDEF_MODE_ENUM +{ + AMF_VIDEO_ENCODER_AV1_CDEF_DISABLE = 0, + AMF_VIDEO_ENCODER_AV1_CDEF_ENABLE_DEFAULT = 1 +}; + +enum AMF_VIDEO_ENCODER_AV1_CDF_FRAME_END_UPDATE_MODE_ENUM +{ + AMF_VIDEO_ENCODER_AV1_CDF_FRAME_END_UPDATE_MODE_DISABLE = 0, + AMF_VIDEO_ENCODER_AV1_CDF_FRAME_END_UPDATE_MODE_ENABLE_DEFAULT = 1 +}; + +enum AMF_VIDEO_ENCODER_AV1_AQ_MODE_ENUM +{ + AMF_VIDEO_ENCODER_AV1_AQ_MODE_NONE = 0, + AMF_VIDEO_ENCODER_AV1_AQ_MODE_CAQ = 1 // Content adaptive quantization mode +}; + +enum AMF_VIDEO_ENCODER_AV1_INTRA_REFRESH_MODE_ENUM +{ + AMF_VIDEO_ENCODER_AV1_INTRA_REFRESH_MODE__DISABLED = 0, + AMF_VIDEO_ENCODER_AV1_INTRA_REFRESH_MODE__GOP_ALIGNED = 1, + AMF_VIDEO_ENCODER_AV1_INTRA_REFRESH_MODE__CONTINUOUS = 2 +}; + + +// *** Static properties - can be set only before Init() *** + +// Encoder Engine Settings +#define AMF_VIDEO_ENCODER_AV1_ENCODER_INSTANCE_INDEX L"Av1EncoderInstanceIndex" // amf_int64; default = 0; selected HW instance idx. The number of instances is queried by using AMF_VIDEO_ENCODER_AV1_CAP_NUM_OF_HW_INSTANCES +#define AMF_VIDEO_ENCODER_AV1_ENCODING_LATENCY_MODE L"Av1EncodingLatencyMode" // amf_int64(AMF_VIDEO_ENCODER_AV1_ENCODING_LATENCY_MODE_ENUM); default = depends on USAGE; The encoding latency mode. +#define AMF_VIDEO_ENCODER_AV1_QUERY_TIMEOUT L"Av1QueryTimeout" // amf_int64; default = 0 (no wait); timeout for QueryOutput call in ms. + +// Usage Settings +#define AMF_VIDEO_ENCODER_AV1_USAGE L"Av1Usage" // amf_int64(AMF_VIDEO_ENCODER_AV1_USAGE_ENUM); default = N/A; Encoder usage. fully configures parameter set. + +// Session Configuration +#define AMF_VIDEO_ENCODER_AV1_FRAMESIZE L"Av1FrameSize" // AMFSize; default = 0,0; Frame size +#define AMF_VIDEO_ENCODER_AV1_COLOR_BIT_DEPTH L"Av1ColorBitDepth" // amf_int64(AMF_COLOR_BIT_DEPTH_ENUM); default = AMF_COLOR_BIT_DEPTH_8 +#define AMF_VIDEO_ENCODER_AV1_PROFILE L"Av1Profile" // amf_int64(AMF_VIDEO_ENCODER_AV1_PROFILE_ENUM) ; default = depends on USAGE; the codec profile of the coded bitstream +#define AMF_VIDEO_ENCODER_AV1_LEVEL L"Av1Level" // amf_int64 (AMF_VIDEO_ENCODER_AV1_LEVEL_ENUM); default = depends on USAGE; the codec level of the coded bitstream +#define AMF_VIDEO_ENCODER_AV1_TILES_PER_FRAME L"Av1NumTilesPerFrame" // amf_int64; default = 1; Number of tiles Per Frame. This is treated as suggestion. The actual number of tiles might be different due to compliance or encoder limitation. +#define AMF_VIDEO_ENCODER_AV1_QUALITY_PRESET L"Av1QualityPreset" // amf_int64(AMF_VIDEO_ENCODER_AV1_QUALITY_PRESET_ENUM); default = depends on USAGE; Quality Preset + +// Codec Configuration +#define AMF_VIDEO_ENCODER_AV1_SCREEN_CONTENT_TOOLS L"Av1ScreenContentTools" // bool; default = depends on USAGE; If true, allow enabling screen content tools by AMF_VIDEO_ENCODER_AV1_PALETTE_MODE_ENABLE and AMF_VIDEO_ENCODER_AV1_FORCE_INTEGER_MV; if false, all screen content tools are disabled. +#define AMF_VIDEO_ENCODER_AV1_ORDER_HINT L"Av1OrderHint" // bool; default = depends on USAGE; If true, code order hint; if false, don't code order hint +#define AMF_VIDEO_ENCODER_AV1_FRAME_ID L"Av1FrameId" // bool; default = depends on USAGE; If true, code frame id; if false, don't code frame id +#define AMF_VIDEO_ENCODER_AV1_TILE_GROUP_OBU L"Av1TileGroupObu" // bool; default = depends on USAGE; If true, code FrameHeaderObu + TileGroupObu and each TileGroupObu contains one tile; if false, code FrameObu. +#define AMF_VIDEO_ENCODER_AV1_CDEF_MODE L"Av1CdefMode" // amd_int64(AMF_VIDEO_ENCODER_AV1_CDEF_MODE_ENUM); default = depends on USAGE; Cdef mode +#define AMF_VIDEO_ENCODER_AV1_ERROR_RESILIENT_MODE L"Av1ErrorResilientMode" // bool; default = depends on USAGE; If true, enable error resilient mode; if false, disable error resilient mode + +// Rate Control and Quality Enhancement +#define AMF_VIDEO_ENCODER_AV1_RATE_CONTROL_METHOD L"Av1RateControlMethod" // amf_int64(AMF_VIDEO_ENCODER_AV1_RATE_CONTROL_METHOD_ENUM); default = depends on USAGE; Rate Control Method +#define AMF_VIDEO_ENCODER_AV1_QVBR_QUALITY_LEVEL L"Av1QvbrQualityLevel" // amf_int64; default = 23; QVBR quality level; range = 1-51 +#define AMF_VIDEO_ENCODER_AV1_INITIAL_VBV_BUFFER_FULLNESS L"Av1InitialVBVBufferFullness" // amf_int64; default = depends on USAGE; Initial VBV Buffer Fullness 0=0% 64=100% + +// Alignment Mode Configuration +#define AMF_VIDEO_ENCODER_AV1_ALIGNMENT_MODE L"Av1AlignmentMode" // amf_int64(AMF_VIDEO_ENCODER_AV1_ALIGNMENT_MODE_ENUM); default = AMF_VIDEO_ENCODER_AV1_ALIGNMENT_MODE_64X16_ONLY; Alignment Mode. + +#define AMF_VIDEO_ENCODER_AV1_PRE_ANALYSIS_ENABLE L"Av1EnablePreAnalysis" // bool; default = depends on USAGE; If true, enables the pre-analysis module. Refer to AMF Video PreAnalysis API reference for more details. If false, disable the pre-analysis module. +#define AMF_VIDEO_ENCODER_AV1_RATE_CONTROL_PREENCODE L"Av1RateControlPreEncode" // bool; default = depends on USAGE; If true, enables pre-encode assist in rate control; if false, disables pre-encode assist in rate control. +#define AMF_VIDEO_ENCODER_AV1_HIGH_MOTION_QUALITY_BOOST L"Av1HighMotionQualityBoost" // bool; default = depends on USAGE; If true, enable high motion quality boost mode; if false, disable high motion quality boost mode. +#define AMF_VIDEO_ENCODER_AV1_AQ_MODE L"Av1AQMode" // amd_int64(AMF_VIDEO_ENCODER_AV1_AQ_MODE_ENUM); default = depends on USAGE; AQ mode + +// Picture Management Configuration +#define AMF_VIDEO_ENCODER_AV1_MAX_NUM_TEMPORAL_LAYERS L"Av1MaxNumOfTemporalLayers" // amf_int64; default = depends on USAGE; Max number of temporal layers might be enabled. The maximum value can be queried from AMF_VIDEO_ENCODER_AV1_CAP_MAX_NUM_TEMPORAL_LAYERS +#define AMF_VIDEO_ENCODER_AV1_MAX_LTR_FRAMES L"Av1MaxNumLTRFrames" // amf_int64; default = depends on USAGE; Max number of LTR frames. The maximum value can be queried from AMF_VIDEO_ENCODER_AV1_CAP_MAX_NUM_LTR_FRAMES +#define AMF_VIDEO_ENCODER_AV1_MAX_NUM_REFRAMES L"Av1MaxNumRefFrames" // amf_int64; default = 1; Maximum number of reference frames + +// color conversion +#define AMF_VIDEO_ENCODER_AV1_INPUT_HDR_METADATA L"Av1InHDRMetadata" // AMFBuffer containing AMFHDRMetadata; default NULL + +// Miscellaneous +#define AMF_VIDEO_ENCODER_AV1_EXTRA_DATA L"Av1ExtraData" // AMFInterface* - > AMFBuffer*; buffer to retrieve coded sequence header + + +// *** Dynamic properties - can be set anytime *** + +// Codec Configuration +#define AMF_VIDEO_ENCODER_AV1_PALETTE_MODE L"Av1PaletteMode" // bool; default = depends on USAGE; If true, enable palette mode; if false, disable palette mode. Valid only when AMF_VIDEO_ENCODER_AV1_SCREEN_CONTENT_TOOLS is true. +#define AMF_VIDEO_ENCODER_AV1_FORCE_INTEGER_MV L"Av1ForceIntegerMv" // bool; default = depends on USAGE; If true, enable force integer MV; if false, disable force integer MV. Valid only when AMF_VIDEO_ENCODER_AV1_SCREEN_CONTENT_TOOLS is true. +#define AMF_VIDEO_ENCODER_AV1_CDF_UPDATE L"Av1CdfUpdate" // bool; default = depends on USAGE; If true, enable CDF update; if false, disable CDF update. +#define AMF_VIDEO_ENCODER_AV1_CDF_FRAME_END_UPDATE_MODE L"Av1CdfFrameEndUpdateMode" // amd_int64(AMF_VIDEO_ENCODER_AV1_CDF_FRAME_END_UPDATE_MODE_ENUM); default = depends on USAGE; CDF frame end update mode + + +// Rate Control and Quality Enhancement +#define AMF_VIDEO_ENCODER_AV1_VBV_BUFFER_SIZE L"Av1VBVBufferSize" // amf_int64; default = depends on USAGE; VBV Buffer Size in bits +#define AMF_VIDEO_ENCODER_AV1_FRAMERATE L"Av1FrameRate" // AMFRate; default = depends on usage; Frame Rate +#define AMF_VIDEO_ENCODER_AV1_ENFORCE_HRD L"Av1EnforceHRD" // bool; default = depends on USAGE; If true, enforce HRD; if false, HRD is not enforced. +#define AMF_VIDEO_ENCODER_AV1_FILLER_DATA L"Av1FillerData" // bool; default = depends on USAGE; If true, code filler data when needed; if false, don't code filler data. +#define AMF_VIDEO_ENCODER_AV1_TARGET_BITRATE L"Av1TargetBitrate" // amf_int64; default = depends on USAGE; Target bit rate in bits +#define AMF_VIDEO_ENCODER_AV1_PEAK_BITRATE L"Av1PeakBitrate" // amf_int64; default = depends on USAGE; Peak bit rate in bits + +#define AMF_VIDEO_ENCODER_AV1_MAX_COMPRESSED_FRAME_SIZE L"Av1MaxCompressedFrameSize" // amf_int64; default = 0; Max compressed frame Size in bits. 0 - no limit +#define AMF_VIDEO_ENCODER_AV1_MIN_Q_INDEX_INTRA L"Av1MinQIndex_Intra" // amf_int64; default = depends on USAGE; Min QIndex for intra frames; range = 0-255 +#define AMF_VIDEO_ENCODER_AV1_MAX_Q_INDEX_INTRA L"Av1MaxQIndex_Intra" // amf_int64; default = depends on USAGE; Max QIndex for intra frames; range = 0-255 +#define AMF_VIDEO_ENCODER_AV1_MIN_Q_INDEX_INTER L"Av1MinQIndex_Inter" // amf_int64; default = depends on USAGE; Min QIndex for inter frames; range = 0-255 +#define AMF_VIDEO_ENCODER_AV1_MAX_Q_INDEX_INTER L"Av1MaxQIndex_Inter" // amf_int64; default = depends on USAGE; Max QIndex for inter frames; range = 0-255 + +#define AMF_VIDEO_ENCODER_AV1_Q_INDEX_INTRA L"Av1QIndex_Intra" // amf_int64; default = depends on USAGE; intra-frame QIndex; range = 0-255 +#define AMF_VIDEO_ENCODER_AV1_Q_INDEX_INTER L"Av1QIndex_Inter" // amf_int64; default = depends on USAGE; inter-frame QIndex; range = 0-255 + +#define AMF_VIDEO_ENCODER_AV1_RATE_CONTROL_SKIP_FRAME L"Av1RateControlSkipFrameEnable" // bool; default = depends on USAGE; If true, rate control may code skip frame when needed; if false, rate control will not code skip frame. + + +// Picture Management Configuration +#define AMF_VIDEO_ENCODER_AV1_GOP_SIZE L"Av1GOPSize" // amf_int64; default = depends on USAGE; GOP Size (distance between automatically inserted key frames). If 0, key frame will be inserted at first frame only. Note that GOP may be interrupted by AMF_VIDEO_ENCODER_AV1_FORCE_FRAME_TYPE. +#define AMF_VIDEO_ENCODER_AV1_HEADER_INSERTION_MODE L"Av1HeaderInsertionMode" // amf_int64(AMF_VIDEO_ENCODER_AV1_HEADER_INSERTION_MODE_ENUM); default = depends on USAGE; sequence header insertion mode +#define AMF_VIDEO_ENCODER_AV1_SWITCH_FRAME_INSERTION_MODE L"Av1SwitchFrameInsertionMode" // amf_int64(AMF_VIDEO_ENCODER_AV1_SWITCH_FRAME_INSERTION_MODE_ENUM); default = depends on USAGE; switch frame insertin mode +#define AMF_VIDEO_ENCODER_AV1_SWITCH_FRAME_INTERVAL L"Av1SwitchFrameInterval" // amf_int64; default = depends on USAGE; the interval between two inserted switch frames. Valid only when AMF_VIDEO_ENCODER_AV1_SWITCH_FRAME_INSERTION_MODE is AMF_VIDEO_ENCODER_AV1_SWITCH_FRAME_INSERTION_MODE_FIXED_INTERVAL. +#define AMF_VIDEO_ENCODER_AV1_NUM_TEMPORAL_LAYERS L"Av1NumTemporalLayers" // amf_int64; default = depends on USAGE; Number of temporal layers. Can be changed at any time but the change is only applied when encoding next base layer frame. + +#define AMF_VIDEO_ENCODER_AV1_INTRA_REFRESH_MODE L"Av1IntraRefreshMode" // amf_int64(AMF_VIDEO_ENCODER_AV1_INTRA_REFRESH_MODE_ENUM); default AMF_VIDEO_ENCODER_AV1_INTRA_REFRESH_MODE__DISABLED +#define AMF_VIDEO_ENCODER_AV1_INTRAREFRESH_STRIPES L"Av1IntraRefreshNumOfStripes" // amf_int64; default = N/A; Valid only when intra refresh is enabled. + +// color conversion +#define AMF_VIDEO_ENCODER_AV1_INPUT_COLOR_PROFILE L"Av1InputColorProfile" // amf_int64(AMF_VIDEO_CONVERTER_COLOR_PROFILE_ENUM); default = AMF_VIDEO_CONVERTER_COLOR_PROFILE_UNKNOWN - mean AUTO by size +#define AMF_VIDEO_ENCODER_AV1_INPUT_TRANSFER_CHARACTERISTIC L"Av1InputColorTransferChar" // amf_int64(AMF_COLOR_TRANSFER_CHARACTERISTIC_ENUM); default = AMF_COLOR_TRANSFER_CHARACTERISTIC_UNDEFINED, ISO/IEC 23001-8_2013 section 7.2 See VideoDecoderUVD.h for enum +#define AMF_VIDEO_ENCODER_AV1_INPUT_COLOR_PRIMARIES L"Av1InputColorPrimaries" // amf_int64(AMF_COLOR_PRIMARIES_ENUM); default = AMF_COLOR_PRIMARIES_UNDEFINED, ISO/IEC 23001-8_2013 section 7.1 See ColorSpace.h for enum + +#define AMF_VIDEO_ENCODER_AV1_OUTPUT_COLOR_PROFILE L"Av1OutputColorProfile" // amf_int64(AMF_VIDEO_CONVERTER_COLOR_PROFILE_ENUM); default = AMF_VIDEO_CONVERTER_COLOR_PROFILE_UNKNOWN - mean AUTO by size +#define AMF_VIDEO_ENCODER_AV1_OUTPUT_TRANSFER_CHARACTERISTIC L"Av1OutputColorTransferChar" // amf_int64(AMF_COLOR_TRANSFER_CHARACTERISTIC_ENUM); default = AMF_COLOR_TRANSFER_CHARACTERISTIC_UNDEFINED, ISO/IEC 23001-8_2013 ?7.2 See VideoDecoderUVD.h for enum +#define AMF_VIDEO_ENCODER_AV1_OUTPUT_COLOR_PRIMARIES L"Av1OutputColorPrimaries" // amf_int64(AMF_COLOR_PRIMARIES_ENUM); default = AMF_COLOR_PRIMARIES_UNDEFINED, ISO/IEC 23001-8_2013 section 7.1 See ColorSpace.h for enum + + +// Frame encode parameters +#define AMF_VIDEO_ENCODER_AV1_FORCE_FRAME_TYPE L"Av1ForceFrameType" // amf_int64(AMF_VIDEO_ENCODER_AV1_FORCE_FRAME_TYPE_ENUM); default = AMF_VIDEO_ENCODER_AV1_FORCE_FRAME_TYPE_NONE; generate particular frame type +#define AMF_VIDEO_ENCODER_AV1_FORCE_INSERT_SEQUENCE_HEADER L"Av1ForceInsertSequenceHeader" // bool; default = false; If true, force insert sequence header with current frame; +#define AMF_VIDEO_ENCODER_AV1_MARK_CURRENT_WITH_LTR_INDEX L"Av1MarkCurrentWithLTRIndex" // amf_int64; default = N/A; Mark current frame with LTR index +#define AMF_VIDEO_ENCODER_AV1_FORCE_LTR_REFERENCE_BITFIELD L"Av1ForceLTRReferenceBitfield" // amf_int64; default = 0; force LTR bit-field +#define AMF_VIDEO_ENCODER_AV1_ROI_DATA L"Av1ROIData" // 2D AMFSurface, surface format: AMF_SURFACE_GRAY32 + +// Encode output parameters +#define AMF_VIDEO_ENCODER_AV1_OUTPUT_FRAME_TYPE L"Av1OutputFrameType" // amf_int64(AMF_VIDEO_ENCODER_AV1_OUTPUT_FRAME_TYPE_ENUM); default = N/A +#define AMF_VIDEO_ENCODER_AV1_OUTPUT_MARKED_LTR_INDEX L"Av1MarkedLTRIndex" // amf_int64; default = N/A; Marked LTR index +#define AMF_VIDEO_ENCODER_AV1_OUTPUT_REFERENCED_LTR_INDEX_BITFIELD L"Av1ReferencedLTRIndexBitfield" // amf_int64; default = N/A; referenced LTR bit-field + +// AV1 Encoder capabilities - exposed in AMFCaps interface +#define AMF_VIDEO_ENCODER_AV1_CAP_NUM_OF_HW_INSTANCES L"Av1CapNumOfHwInstances" // amf_int64; default = N/A; number of HW encoder instances +#define AMF_VIDEO_ENCODER_AV1_CAP_MAX_THROUGHPUT L"Av1CapMaxThroughput" // amf_int64; default = N/A; MAX throughput for AV1 encoder in MB (16 x 16 pixel) +#define AMF_VIDEO_ENCODER_AV1_CAP_REQUESTED_THROUGHPUT L"Av1CapRequestedThroughput" // amf_int64; default = N/A; Currently total requested throughput for AV1 encode in MB (16 x 16 pixel) +#define AMF_VIDEO_ENCODER_AV1_CAP_COLOR_CONVERSION L"Av1CapColorConversion" // amf_int64(AMF_ACCELERATION_TYPE); default = N/A; type of supported color conversion. default AMF_ACCEL_GPU +#define AMF_VIDEO_ENCODER_AV1_CAP_PRE_ANALYSIS L"Av1PreAnalysis" // amf_bool - pre analysis module is available for AV1 UVE encoder, n/a for the other encoders +#define AMF_VIDEO_ENCODER_AV1_CAP_MAX_BITRATE L"Av1MaxBitrate" // amf_int64; default = N/A; Maximum bit rate in bits +#define AMF_VIDEO_ENCODER_AV1_CAP_MAX_PROFILE L"Av1MaxProfile" // amf_int64(AMF_VIDEO_ENCODER_AV1_PROFILE_ENUM); default = N/A; max value of code profile +#define AMF_VIDEO_ENCODER_AV1_CAP_MAX_LEVEL L"Av1MaxLevel" // amf_int64(AMF_VIDEO_ENCODER_AV1_LEVEL_ENUM); default = N/A; max value of codec level +#define AMF_VIDEO_ENCODER_AV1_CAP_MAX_NUM_TEMPORAL_LAYERS L"Av1CapMaxNumTemporalLayers" // amf_int64; default = N/A; The cap of maximum number of temporal layers +#define AMF_VIDEO_ENCODER_AV1_CAP_MAX_NUM_LTR_FRAMES L"Av1CapMaxNumLTRFrames" // amf_int64; default = N/A; The cap of maximum number of LTR frames. This value is calculated based on current value of AMF_VIDEO_ENCODER_AV1_MAX_NUM_TEMPORAL_LAYERS. + +#endif //#ifndef AMF_VideoEncoderAV1_h
View file
obs-studio-28.1.2.tar.xz/plugins/obs-ffmpeg/external/AMF/include/components/VideoEncoderHEVC.h -> obs-studio-29.0.0.tar.xz/plugins/obs-ffmpeg/external/AMF/include/components/VideoEncoderHEVC.h
Changed
@@ -80,7 +80,10 @@ AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD_CONSTANT_QP = 0, AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD_LATENCY_CONSTRAINED_VBR, AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD_PEAK_CONSTRAINED_VBR, - AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD_CBR + AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD_CBR, + AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD_QUALITY_VBR, + AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD_HIGH_QUALITY_VBR, + AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD_HIGH_QUALITY_CBR }; enum AMF_VIDEO_ENCODER_HEVC_PICTURE_TYPE_ENUM @@ -145,9 +148,10 @@ #define AMF_VIDEO_ENCODER_HEVC_QUALITY_PRESET L"HevcQualityPreset" // amf_int64(AMF_VIDEO_ENCODER_HEVC_QUALITY_PRESET_ENUM); default = depends on USAGE; Quality Preset #define AMF_VIDEO_ENCODER_HEVC_EXTRADATA L"HevcExtraData" // AMFInterface* - > AMFBuffer*; SPS/PPS buffer - read-only #define AMF_VIDEO_ENCODER_HEVC_ASPECT_RATIO L"HevcAspectRatio" // AMFRatio; default = 1, 1 -#define AMF_VIDEO_ENCODER_HEVC_LOWLATENCY_MODE L"LowLatencyInternal" // bool; default = false, enables low latency mode +#define AMF_VIDEO_ENCODER_HEVC_LOWLATENCY_MODE L"LowLatencyInternal" // bool; default = false, enables low latency mode #define AMF_VIDEO_ENCODER_HEVC_PRE_ANALYSIS_ENABLE L"HevcEnablePreAnalysis" // bool; default = false; enables the pre-analysis module. Currently only works in AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD_PEAK_CONSTRAINED_VBR mode. Refer to AMF Video PreAnalysis API reference for more details. -#define AMF_VIDEO_ENCODER_HEVC_NOMINAL_RANGE L"HevcNominalRange" // amf_int64(AMF_VIDEO_ENCODER_HEVC_NOMINAL_RANGE); default = amf_int64(AMF_VIDEO_ENCODER_HEVC_NOMINAL_RANGE_STUDIO); property is bool but amf_int64 also works for backward compatibility. +#define AMF_VIDEO_ENCODER_HEVC_NOMINAL_RANGE L"HevcNominalRange" // amf_int64(AMF_VIDEO_ENCODER_HEVC_NOMINAL_RANGE); default = amf_int64(AMF_VIDEO_ENCODER_HEVC_NOMINAL_RANGE_STUDIO); property is bool but amf_int64 also works for backward compatibility. +#define AMF_VIDEO_ENCODER_HEVC_MAX_NUM_TEMPORAL_LAYERS L"HevcMaxNumOfTemporalLayers" // amf_int64; default = 1; Max number of temporal layers. // Picture control properties #define AMF_VIDEO_ENCODER_HEVC_NUM_GOPS_PER_IDR L"HevcGOPSPerIDR" // amf_int64; default = 1; The frequency to insert IDR as start of a GOP. 0 means no IDR will be inserted. @@ -159,6 +163,7 @@ // Rate control properties #define AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD L"HevcRateControlMethod" // amf_int64(AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD_ENUM); default = depends on USAGE; Rate Control Method +#define AMF_VIDEO_ENCODER_HEVC_QVBR_QUALITY_LEVEL L"HevcQvbrQualityLevel" // amf_int64; default = 23; QVBR quality level; range = 1-51 #define AMF_VIDEO_ENCODER_HEVC_VBV_BUFFER_SIZE L"HevcVBVBufferSize" // amf_int64; default = depends on USAGE; VBV Buffer Size in bits #define AMF_VIDEO_ENCODER_HEVC_INITIAL_VBV_BUFFER_FULLNESS L"HevcInitialVBVBufferFullness" // amf_int64; default = 64; Initial VBV Buffer Fullness 0=0% 64=100% #define AMF_VIDEO_ENCODER_HEVC_ENABLE_VBAQ L"HevcEnableVBAQ" // // bool; default = depends on USAGE; Enable auto VBAQ @@ -213,6 +218,9 @@ #define AMF_VIDEO_ENCODER_HEVC_INPUT_HDR_METADATA L"HevcInHDRMetadata" // AMFBuffer containing AMFHDRMetadata; default NULL //#define AMF_VIDEO_ENCODER_HEVC_OUTPUT_HDR_METADATA L"HevcOutHDRMetadata" // AMFBuffer containing AMFHDRMetadata; default NULL +// SVC +#define AMF_VIDEO_ENCODER_HEVC_NUM_TEMPORAL_LAYERS L"HevcNumOfTemporalLayers" // amf_int64; default = 1; Number of temporal layers. Can be changed at any time but the change is only applied when encoding next base layer frame. + // DPB management #define AMF_VIDEO_ENCODER_HEVC_PICTURE_TRANSFER_MODE L"HevcPicTransferMode" // amf_int64(AMF_VIDEO_ENCODER_HEVC_PICTURE_TRANSFER_MODE_ENUM); default = AMF_VIDEO_ENCODER_HEVC_PICTURE_TRANSFER_MODE_OFF - whether to exchange reference/reconstructed pic between encoder and application @@ -282,6 +290,7 @@ #define AMF_VIDEO_ENCODER_HEVC_CAP_MAX_LEVEL L"HevcMaxLevel" // amf_int64 maximum profile level #define AMF_VIDEO_ENCODER_HEVC_CAP_MIN_REFERENCE_FRAMES L"HevcMinReferenceFrames" // amf_int64 minimum number of reference frames #define AMF_VIDEO_ENCODER_HEVC_CAP_MAX_REFERENCE_FRAMES L"HevcMaxReferenceFrames" // amf_int64 maximum number of reference frames +#define AMF_VIDEO_ENCODER_HEVC_CAP_MAX_TEMPORAL_LAYERS L"HevcMaxTemporalLayers" // amf_int64 maximum number of temporal layers #define AMF_VIDEO_ENCODER_HEVC_CAP_NUM_OF_HW_INSTANCES L"HevcNumOfHwInstances" // amf_int64 number of HW encoder instances #define AMF_VIDEO_ENCODER_HEVC_CAP_COLOR_CONVERSION L"HevcColorConversion" // amf_int64(AMF_ACCELERATION_TYPE) - type of supported color conversion. default AMF_ACCEL_GPU #define AMF_VIDEO_ENCODER_HEVC_CAP_PRE_ANALYSIS L"HevcPreAnalysis" // amf_bool - pre analysis module is available for HEVC UVE encoder, n/a for the other encoders
View file
obs-studio-28.1.2.tar.xz/plugins/obs-ffmpeg/external/AMF/include/components/VideoEncoderVCE.h -> obs-studio-29.0.0.tar.xz/plugins/obs-ffmpeg/external/AMF/include/components/VideoEncoderVCE.h
Changed
@@ -79,7 +79,9 @@ AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_CBR, AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_PEAK_CONSTRAINED_VBR, AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_LATENCY_CONSTRAINED_VBR, - AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_QUALITY_VBR + AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_QUALITY_VBR, + AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_HIGH_QUALITY_VBR, + AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_HIGH_QUALITY_CBR }; enum AMF_VIDEO_ENCODER_QUALITY_PRESET_ENUM @@ -164,6 +166,7 @@ #define AMF_VIDEO_ENCODER_RATE_CONTROL_PREANALYSIS_ENABLE L"RateControlPreanalysisEnable" // amf_int64(AMF_VIDEO_ENCODER_PREENCODE_MODE_ENUM); default = AMF_VIDEO_ENCODER_PREENCODE_DISABLED; enables pre-encode assisted rate control. Deprecated, please use AMF_VIDEO_ENCODER_PREENCODE_ENABLE instead. #define AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD L"RateControlMethod" // amf_int64(AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_ENUM); default = depends on USAGE; Rate Control Method #define AMF_VIDEO_ENCODER_QVBR_QUALITY_LEVEL L"QvbrQualityLevel" // amf_int64; default = 23; QVBR quality level; range = 1-51 +#define AMF_VIDEO_ENCODER_MAX_NUM_TEMPORAL_LAYERS L"MaxNumOfTemporalLayers" // amf_int64; default = 1; Max number of temporal layers. #if !defined(__GNUC__) && !defined(__clang__) #pragma deprecated("AMF_VIDEO_ENCODER_RATE_CONTROL_PREANALYSIS_ENABLE") #endif
View file
obs-studio-28.1.2.tar.xz/plugins/obs-ffmpeg/external/AMF/include/core/Version.h -> obs-studio-29.0.0.tar.xz/plugins/obs-ffmpeg/external/AMF/include/core/Version.h
Changed
@@ -51,7 +51,7 @@ #define AMF_VERSION_MAJOR 1 #define AMF_VERSION_MINOR 4 -#define AMF_VERSION_RELEASE 24 +#define AMF_VERSION_RELEASE 29 #define AMF_VERSION_BUILD_NUM 0 #define AMF_FULL_VERSION AMF_MAKE_FULL_VERSION(AMF_VERSION_MAJOR, AMF_VERSION_MINOR, AMF_VERSION_RELEASE, AMF_VERSION_BUILD_NUM)
View file
obs-studio-28.1.2.tar.xz/plugins/obs-ffmpeg/ffmpeg-mux/ffmpeg-mux.c -> obs-studio-29.0.0.tar.xz/plugins/obs-ffmpeg/ffmpeg-mux/ffmpeg-mux.c
Changed
@@ -99,9 +99,11 @@ int color_trc; int colorspace; int color_range; + int chroma_sample_location; int max_luminance; char *acodec; char *muxer_settings; + int codec_tag; }; struct audio_params { @@ -368,6 +370,9 @@ if (!get_opt_int(argc, argv, ¶ms->color_range, "video color range")) return false; + if (!get_opt_int(argc, argv, ¶ms->chroma_sample_location, + "video chroma sample location")) + return false; if (!get_opt_int(argc, argv, ¶ms->max_luminance, "video max luminance")) return false; @@ -375,6 +380,9 @@ return false; if (!get_opt_int(argc, argv, ¶ms->fps_den, "video fps den")) return false; + if (!get_opt_int(argc, argv, ¶ms->codec_tag, + "video codec tag")) + params->codec_tag = 0; } if (params->tracks) { @@ -445,6 +453,7 @@ context = avcodec_alloc_context3(NULL); context->codec_type = codec->type; context->codec_id = codec->id; + context->codec_tag = ffm->params.codec_tag; context->bit_rate = (int64_t)ffm->params.vbitrate * 1000; context->width = ffm->params.width; context->height = ffm->params.height; @@ -454,10 +463,7 @@ context->color_trc = ffm->params.color_trc; context->colorspace = ffm->params.colorspace; context->color_range = ffm->params.color_range; - context->chroma_sample_location = - (ffm->params.colorspace == AVCOL_SPC_BT2020_NCL) - ? AVCHROMA_LOC_TOPLEFT - : AVCHROMA_LOC_LEFT; + context->chroma_sample_location = ffm->params.chroma_sample_location; context->extradata = extradata; context->extradata_size = ffm->video_header.size; context->time_base = @@ -515,6 +521,7 @@ AVStream *stream; void *extradata = NULL; const char *name = ffm->params.acodec; + int channels; const AVCodecDescriptor *codec = avcodec_descriptor_get_by_name(name); if (!codec) { @@ -538,7 +545,10 @@ context->codec_type = codec->type; context->codec_id = codec->id; context->bit_rate = (int64_t)ffm->audioidx.abitrate * 1000; - context->channels = ffm->audioidx.channels; + channels = ffm->audioidx.channels; +#if LIBAVUTIL_VERSION_INT < AV_VERSION_INT(57, 24, 100) + context->channels = channels; +#endif context->sample_rate = ffm->audioidx.sample_rate; context->frame_size = ffm->audioidx.frame_size; context->sample_fmt = AV_SAMPLE_FMT_S16; @@ -546,15 +556,14 @@ context->extradata = extradata; context->extradata_size = ffm->audio_headeridx.size; #if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(59, 24, 100) - context->channel_layout = - av_get_default_channel_layout(context->channels); + context->channel_layout = av_get_default_channel_layout(channels); //avutil default channel layout for 5 channels is 5.0 ; fix for 4.1 - if (context->channels == 5) + if (channels == 5) context->channel_layout = av_get_channel_layout("4.1"); #else - av_channel_layout_default(&context->ch_layout, context->channels); + av_channel_layout_default(&context->ch_layout, channels); //avutil default channel layout for 5 channels is 5.0 ; fix for 4.1 - if (context->channels == 5) + if (channels == 5) context->ch_layout = (AVChannelLayout)AV_CHANNEL_LAYOUT_4POINT1; #endif if (ffm->output->oformat->flags & AVFMT_GLOBALHEADER)
View file
obs-studio-28.1.2.tar.xz/plugins/obs-ffmpeg/jim-nvenc-helpers.c -> obs-studio-29.0.0.tar.xz/plugins/obs-ffmpeg/jim-nvenc-helpers.c
Changed
@@ -2,6 +2,7 @@ #include <util/platform.h> #include <util/threading.h> #include <util/config-file.h> +#include <util/windows/device-enum.h> #include <util/dstr.h> #include <util/pipe.h> @@ -222,14 +223,26 @@ #endif extern struct obs_encoder_info av1_nvenc_info; +static bool enum_luids(void *param, uint32_t idx, uint64_t luid) +{ + struct dstr *cmd = param; + dstr_catf(cmd, " %llX", luid); + UNUSED_PARAMETER(idx); + return true; +} + static bool av1_supported(void) { char *test_exe = os_get_executable_path_ptr("obs-nvenc-test.exe"); + struct dstr cmd = {0}; struct dstr caps_str = {0}; bool av1_supported = false; config_t *config = NULL; - os_process_pipe_t *pp = os_process_pipe_create(test_exe, "r"); + dstr_copy(&cmd, test_exe); + enum_graphics_device_luids(enum_luids, &cmd); + + os_process_pipe_t *pp = os_process_pipe_create(cmd.array, "r"); if (!pp) { blog(LOG_WARNING, "NVENC Failed to launch the NVENC " "test process I guess"); @@ -278,6 +291,7 @@ if (config) config_close(config); dstr_free(&caps_str); + dstr_free(&cmd); if (test_exe) bfree(test_exe);
View file
obs-studio-28.1.2.tar.xz/plugins/obs-ffmpeg/jim-nvenc.c -> obs-studio-29.0.0.tar.xz/plugins/obs-ffmpeg/jim-nvenc.c
Changed
@@ -431,7 +431,7 @@ } static bool init_encoder_base(struct nvenc_data *enc, obs_data_t *settings, - int bf, bool psycho_aq, bool *lossless) + int bf, bool compatibility, bool *lossless) { const char *rc = obs_data_get_string(settings, "rate_control"); int bitrate = (int)obs_data_get_int(settings, "bitrate"); @@ -445,6 +445,8 @@ const char *profile = obs_data_get_string(settings, "profile"); bool lookahead = obs_data_get_bool(settings, "lookahead"); bool vbr = astrcmpi(rc, "VBR") == 0; + bool psycho_aq = !compatibility && + obs_data_get_bool(settings, "psycho_aq"); NVENCSTATUS err; video_t *video = obs_encoder_video(enc->encoder); @@ -458,7 +460,9 @@ GUID nv_preset = get_nv_preset2(preset2); NV_ENC_TUNING_INFO nv_tuning = get_nv_tuning(tuning); - NV_ENC_MULTI_PASS nv_multipass = get_nv_multipass(multipass); + NV_ENC_MULTI_PASS nv_multipass = compatibility + ? NV_ENC_MULTI_PASS_DISABLED + : get_nv_multipass(multipass); if (obs_data_has_user_value(settings, "preset") && !obs_data_has_user_value(settings, "preset2") && @@ -627,12 +631,14 @@ } /* psycho aq */ - if (nv_get_cap(enc, NV_ENC_CAPS_SUPPORT_TEMPORAL_AQ)) { - config->rcParams.enableAQ = psycho_aq; - config->rcParams.aqStrength = 8; - config->rcParams.enableTemporalAQ = psycho_aq; - } else if (psycho_aq) { - warn("Ignoring Psycho Visual Tuning request since GPU is not capable"); + if (!compatibility) { + if (nv_get_cap(enc, NV_ENC_CAPS_SUPPORT_TEMPORAL_AQ)) { + config->rcParams.enableAQ = psycho_aq; + config->rcParams.aqStrength = 8; + config->rcParams.enableTemporalAQ = psycho_aq; + } else { + warn("Ignoring Psycho Visual Tuning request since GPU is not capable"); + } } /* -------------------------- */ @@ -694,14 +700,14 @@ } static bool init_encoder_h264(struct nvenc_data *enc, obs_data_t *settings, - int bf, bool psycho_aq) + int bf, bool compatibility) { const char *rc = obs_data_get_string(settings, "rate_control"); int keyint_sec = (int)obs_data_get_int(settings, "keyint_sec"); const char *profile = obs_data_get_string(settings, "profile"); bool lossless; - if (!init_encoder_base(enc, settings, bf, psycho_aq, &lossless)) { + if (!init_encoder_base(enc, settings, bf, compatibility, &lossless)) { return false; } @@ -779,14 +785,14 @@ } static bool init_encoder_hevc(struct nvenc_data *enc, obs_data_t *settings, - int bf, bool psycho_aq) + int bf, bool compatibility) { const char *rc = obs_data_get_string(settings, "rate_control"); int keyint_sec = (int)obs_data_get_int(settings, "keyint_sec"); const char *profile = obs_data_get_string(settings, "profile"); bool lossless; - if (!init_encoder_base(enc, settings, bf, psycho_aq, &lossless)) { + if (!init_encoder_base(enc, settings, bf, compatibility, &lossless)) { return false; } @@ -880,13 +886,13 @@ } static bool init_encoder_av1(struct nvenc_data *enc, obs_data_t *settings, - int bf, bool psycho_aq) + int bf, bool compatibility) { const char *rc = obs_data_get_string(settings, "rate_control"); int keyint_sec = (int)obs_data_get_int(settings, "keyint_sec"); bool lossless; - if (!init_encoder_base(enc, settings, bf, psycho_aq, &lossless)) { + if (!init_encoder_base(enc, settings, bf, compatibility, &lossless)) { return false; } @@ -987,15 +993,15 @@ static void nvenc_destroy(void *data); static bool init_specific_encoder(struct nvenc_data *enc, obs_data_t *settings, - int bf, bool psycho_aq) + int bf, bool compatibility) { switch (enc->codec) { case CODEC_HEVC: - return init_encoder_hevc(enc, settings, bf, psycho_aq); + return init_encoder_hevc(enc, settings, bf, compatibility); case CODEC_H264: - return init_encoder_h264(enc, settings, bf, psycho_aq); + return init_encoder_h264(enc, settings, bf, compatibility); case CODEC_AV1: - return init_encoder_av1(enc, settings, bf, psycho_aq); + return init_encoder_av1(enc, settings, bf, compatibility); } return false; @@ -1005,7 +1011,6 @@ obs_data_t *settings, obs_encoder_t *encoder) { int bf = (int)obs_data_get_int(settings, "bf"); - const bool psycho_aq = obs_data_get_bool(settings, "psycho_aq"); const bool support_10bit = nv_get_cap(enc, NV_ENC_CAPS_SUPPORT_10BIT_ENCODE); const int bf_max = nv_get_cap(enc, NV_ENC_CAPS_NUM_MAX_BFRAMES); @@ -1038,12 +1043,9 @@ bf = bf_max; } - if (!init_specific_encoder(enc, settings, bf, psycho_aq)) { - if (!psycho_aq) - return false; - + if (!init_specific_encoder(enc, settings, bf, false)) { blog(LOG_WARNING, "jim-nvenc init_specific_encoder failed, " - "trying again without Psycho Visual Tuning"); + "trying again with compatibility options"); nv.nvEncDestroyEncoder(enc->session); enc->session = NULL; @@ -1051,7 +1053,8 @@ if (!init_session(enc)) { return false; } - if (!init_specific_encoder(enc, settings, bf, false)) { + /* try without multipass and psycho aq */ + if (!init_specific_encoder(enc, settings, bf, true)) { return false; } }
View file
obs-studio-28.1.2.tar.xz/plugins/obs-ffmpeg/obs-amf-test/obs-amf-test.cpp -> obs-studio-29.0.0.tar.xz/plugins/obs-ffmpeg/obs-amf-test/obs-amf-test.cpp
Changed
@@ -2,6 +2,7 @@ #include "../external/AMF/include/core/Trace.h" #include "../external/AMF/include/components/VideoEncoderVCE.h" #include "../external/AMF/include/components/VideoEncoderHEVC.h" +#include "../external/AMF/include/components/VideoEncoderAV1.h" #include <util/windows/ComPtr.hpp> @@ -9,6 +10,7 @@ #include <d3d11.h> #include <d3d11_1.h> +#include <vector> #include <string> #include <map> @@ -24,9 +26,11 @@ bool is_amd = false; bool supports_avc = false; bool supports_hevc = false; + bool supports_av1 = false; }; static AMFFactory *amf_factory = nullptr; +static std::vector<uint64_t> luid_order; static std::map<uint32_t, adapter_caps> adapter_info; static bool has_encoder(AMFContextPtr &amf_context, const wchar_t *encoder_name) @@ -37,6 +41,17 @@ return res == AMF_OK; } +static inline uint32_t get_adapter_idx(uint32_t adapter_idx, LUID luid) +{ + for (size_t i = 0; i < luid_order.size(); i++) { + if (luid_orderi == *(uint64_t *)&luid) { + return (uint32_t)i; + } + } + + return adapter_idx; +} + static bool get_adapter_caps(IDXGIFactory *factory, uint32_t adapter_idx) { AMF_RESULT res; @@ -47,21 +62,17 @@ if (FAILED(hr)) return false; - adapter_caps &caps = adapter_infoadapter_idx; - DXGI_ADAPTER_DESC desc; adapter->GetDesc(&desc); + uint32_t luid_idx = get_adapter_idx(adapter_idx, desc.AdapterLuid); + adapter_caps &caps = adapter_infoluid_idx; + if (desc.VendorId != AMD_VENDOR_ID) return true; caps.is_amd = true; - ComPtr<IDXGIOutput> output; - hr = adapter->EnumOutputs(0, &output); - if (FAILED(hr)) - return true; - ComPtr<ID3D11Device> device; ComPtr<ID3D11DeviceContext> context; hr = D3D11CreateDevice(adapter, D3D_DRIVER_TYPE_UNKNOWN, nullptr, 0, @@ -81,6 +92,7 @@ caps.supports_avc = has_encoder(amf_context, AMFVideoEncoderVCE_AVC); caps.supports_hevc = has_encoder(amf_context, AMFVideoEncoder_HEVC); + caps.supports_av1 = has_encoder(amf_context, AMFVideoEncoder_AV1); return true; } @@ -98,7 +110,7 @@ return 0; } -int main(void) +int main(int argc, char *argv) try { ComPtr<IDXGIFactory> factory; AMF_RESULT res; @@ -130,6 +142,16 @@ if (res != AMF_OK) throw "AMFInit failed"; + /* --------------------------------------------------------- */ + /* parse expected LUID order */ + + for (int i = 1; i < argc; i++) { + luid_order.push_back(strtoull(argvi, NULL, 16)); + } + + /* --------------------------------------------------------- */ + /* obtain adapter compatibility information */ + hr = CreateDXGIFactory1(__uuidof(IDXGIFactory), (void **)&factory); if (FAILED(hr)) throw "CreateDXGIFactory1 failed"; @@ -145,6 +167,8 @@ caps.supports_avc ? "true" : "false"); printf("supports_hevc=%s\n", caps.supports_hevc ? "true" : "false"); + printf("supports_av1=%s\n", + caps.supports_av1 ? "true" : "false"); } return 0;
View file
obs-studio-28.1.2.tar.xz/plugins/obs-ffmpeg/obs-ffmpeg-audio-encoders.c -> obs-studio-29.0.0.tar.xz/plugins/obs-ffmpeg/obs-ffmpeg-audio-encoders.c
Changed
@@ -116,6 +116,7 @@ static bool initialize_codec(struct enc_encoder *enc) { int ret; + int channels; enc->aframe = av_frame_alloc(); if (!enc->aframe) { @@ -134,7 +135,12 @@ return false; } enc->aframe->format = enc->context->sample_fmt; +#if LIBAVUTIL_VERSION_INT < AV_VERSION_INT(57, 24, 100) enc->aframe->channels = enc->context->channels; + channels = enc->context->channels; +#else + channels = enc->context->ch_layout.nb_channels; +#endif #if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(59, 24, 100) enc->aframe->channel_layout = enc->context->channel_layout; #else @@ -148,8 +154,8 @@ enc->frame_size_bytes = enc->frame_size * (int)enc->audio_size; - ret = av_samples_alloc(enc->samples, NULL, enc->context->channels, - enc->frame_size, enc->context->sample_fmt, 0); + ret = av_samples_alloc(enc->samples, NULL, channels, enc->frame_size, + enc->context->sample_fmt, 0); if (ret < 0) { warn("Failed to create audio buffer: %s", av_err2str(ret)); return false; @@ -216,16 +222,21 @@ enc->context->bit_rate = bitrate * 1000; const struct audio_output_info *aoi; aoi = audio_output_get_info(audio); + +#if LIBAVUTIL_VERSION_INT < AV_VERSION_INT(57, 24, 100) enc->context->channels = (int)audio_output_get_channels(audio); +#endif + #if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(59, 24, 100) enc->context->channel_layout = convert_speaker_layout(aoi->speakers); #else av_channel_layout_default(&enc->context->ch_layout, - enc->context->channels); + (int)audio_output_get_channels(audio)); if (aoi->speakers == SPEAKERS_4POINT1) enc->context->ch_layout = (AVChannelLayout)AV_CHANNEL_LAYOUT_4POINT1; #endif + enc->context->sample_rate = audio_output_get_sample_rate(audio); enc->context->sample_fmt = enc->codec->sample_fmts ? enc->codec->sample_fmts0 @@ -264,7 +275,7 @@ av_channel_layout_describe(&enc->context->ch_layout, buf, 256); info("bitrate: %" PRId64 ", channels: %d, channel_layout: %s\n", (int64_t)enc->context->bit_rate / 1000, - (int)enc->context->channels, buf); + (int)enc->context->ch_layout.nb_channels, buf); #endif init_sizes(enc, audio); @@ -298,6 +309,7 @@ AVPacket avpacket = {0}; int got_packet; int ret; + int channels; enc->aframe->nb_samples = enc->frame_size; enc->aframe->pts = av_rescale_q( @@ -305,11 +317,14 @@ enc->context->time_base); #if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(57, 24, 100) enc->aframe->ch_layout = enc->context->ch_layout; + channels = enc->context->ch_layout.nb_channels; +#else + channels = enc->context->channels; #endif - ret = avcodec_fill_audio_frame( - enc->aframe, enc->context->channels, enc->context->sample_fmt, - enc->samples0, enc->frame_size_bytes * enc->context->channels, - 1); + ret = avcodec_fill_audio_frame(enc->aframe, channels, + enc->context->sample_fmt, + enc->samples0, + enc->frame_size_bytes * channels, 1); if (ret < 0) { warn("avcodec_fill_audio_frame failed: %s", av_err2str(ret)); return false; @@ -391,10 +406,16 @@ static void enc_audio_info(void *data, struct audio_convert_info *info) { struct enc_encoder *enc = data; + int channels; +#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(57, 24, 100) + channels = enc->context->ch_layout.nb_channels; +#else + channels = enc->context->channels; +#endif info->format = convert_ffmpeg_sample_format(enc->context->sample_fmt); info->samples_per_sec = (uint32_t)enc->context->sample_rate; - if (enc->context->channels != 7 && enc->context->channels <= 8) - info->speakers = (enum speaker_layout)(enc->context->channels); + if (channels != 7 && channels <= 8) + info->speakers = (enum speaker_layout)(channels); else info->speakers = SPEAKERS_UNKNOWN; }
View file
obs-studio-28.1.2.tar.xz/plugins/obs-ffmpeg/obs-ffmpeg-av1.c -> obs-studio-29.0.0.tar.xz/plugins/obs-ffmpeg/obs-ffmpeg-av1.c
Changed
@@ -26,9 +26,14 @@ #define info(format, ...) do_log(LOG_INFO, format, ##__VA_ARGS__) #define debug(format, ...) do_log(LOG_DEBUG, format, ##__VA_ARGS__) +enum av1_encoder_type { + AV1_ENCODER_TYPE_AOM, + AV1_ENCODER_TYPE_SVT, +}; + struct av1_encoder { struct ffmpeg_video_encoder ffve; - bool svtav1; + enum av1_encoder_type type; DARRAY(uint8_t) header; }; @@ -66,6 +71,7 @@ int cqp = (int)obs_data_get_int(settings, "cqp"); int keyint_sec = (int)obs_data_get_int(settings, "keyint_sec"); int preset = (int)obs_data_get_int(settings, "preset"); + AVDictionary *svtav1_opts = NULL; video_t *video = obs_encoder_video(enc->ffve.encoder); const struct video_output_info *voi = video_output_get_info(video); @@ -78,9 +84,18 @@ enc->ffve.context->thread_count = 0; av1_video_info(enc, &info); - av_opt_set_int(enc->ffve.context->priv_data, - enc->svtav1 ? "preset" : "cpu-used", preset, 0); - if (!enc->svtav1) { + + if (enc->type == AV1_ENCODER_TYPE_SVT) { + av_opt_set_int(enc->ffve.context->priv_data, "preset", preset, + 0); +#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(59, 37, 100) + av_dict_set_int(&svtav1_opts, "rc", 1, 0); +#else + av_opt_set(enc->ffve.context->priv_data, "rc", "vbr", 0); +#endif + } else if (enc->type == AV1_ENCODER_TYPE_AOM) { + av_opt_set_int(enc->ffve.context->priv_data, "cpu-used", preset, + 0); av_opt_set(enc->ffve.context->priv_data, "usage", "realtime", 0); #if 0 @@ -94,31 +109,53 @@ av_opt_set_int(enc->ffve.context->priv_data, "row-mt", 1, 0); } - if (enc->svtav1) - av_opt_set(enc->ffve.context->priv_data, "rc", "vbr", 0); - if (astrcmpi(rc, "cqp") == 0) { bitrate = 0; - enc->ffve.context->global_quality = cqp; + av_opt_set_int(enc->ffve.context->priv_data, "crf", cqp, 0); - if (enc->svtav1) + if (enc->type == AV1_ENCODER_TYPE_SVT) { +#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(59, 37, 100) + av_dict_set_int(&svtav1_opts, "rc", 0, 0); + av_opt_set_int(enc->ffve.context->priv_data, "qp", cqp, + 0); +#else av_opt_set(enc->ffve.context->priv_data, "rc", "cqp", 0); + av_opt_set_int(enc->ffve.context->priv_data, "qp", cqp, + 0); +#endif + } } else if (astrcmpi(rc, "vbr") != 0) { /* CBR by default */ const int64_t rate = bitrate * INT64_C(1000); - enc->ffve.context->rc_max_rate = rate; enc->ffve.context->rc_min_rate = rate; cqp = 0; - if (enc->svtav1) + if (enc->type == AV1_ENCODER_TYPE_SVT) { +#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(59, 37, 100) + av_dict_set_int(&svtav1_opts, "rc", 2, 0); + av_dict_set_int(&svtav1_opts, "pred-struct", 1, 0); + av_dict_set_int(&svtav1_opts, "bias-pct", 0, 0); + av_dict_set_int(&svtav1_opts, "tbr", rate, 0); +#else + enc->ffve.context->rc_max_rate = rate; av_opt_set(enc->ffve.context->priv_data, "rc", "cvbr", 0); +#endif + } else { + enc->ffve.context->rc_max_rate = rate; + } + } + + if (enc->type == AV1_ENCODER_TYPE_SVT) { + av_opt_set_dict_val(enc->ffve.context->priv_data, "svtav1_opts", + svtav1_opts, 0); } const char *ffmpeg_opts = obs_data_get_string(settings, "ffmpeg_opts"); ffmpeg_video_encoder_update(&enc->ffve, bitrate, keyint_sec, voi, &info, ffmpeg_opts); + av_dict_free(&svtav1_opts); info("settings:\n" "\tencoder: %s\n" @@ -150,7 +187,7 @@ { struct av1_encoder *enc = data; - if (enc->svtav1) { + if (enc->type == AV1_ENCODER_TYPE_SVT) { da_copy_array(enc->header, enc->ffve.context->extradata, enc->ffve.context->extradata_size); } else { @@ -192,7 +229,9 @@ struct av1_encoder *enc = bzalloc(sizeof(*enc)); if (strcmp(enc_lib, "libsvtav1") == 0) - enc->svtav1 = true; + enc->type = AV1_ENCODER_TYPE_SVT; + else if (strcmp(enc_lib, "libaom-av1") == 0) + enc->type = AV1_ENCODER_TYPE_AOM; if (!ffmpeg_video_encoder_init(&enc->ffve, enc, encoder, enc_lib, NULL, enc_name, NULL, on_first_packet)) @@ -250,7 +289,7 @@ return true; } -obs_properties_t *av1_properties(bool svtav1) +obs_properties_t *av1_properties(enum av1_encoder_type type) { obs_properties_t *props = obs_properties_create(); obs_property_t *p; @@ -280,7 +319,7 @@ p = obs_properties_add_list(props, "preset", obs_module_text("Preset"), OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT); - if (svtav1) { + if (type == AV1_ENCODER_TYPE_SVT) { obs_property_list_add_int(p, "Very likely too slow (6)", 6); obs_property_list_add_int(p, "Probably too slow (7)", 7); obs_property_list_add_int(p, "Seems okay (8)", 8); @@ -290,7 +329,7 @@ obs_property_list_add_int( p, "Whoa, although quality might be not so great (12)", 12); - } else { + } else if (type == AV1_ENCODER_TYPE_AOM) { obs_property_list_add_int(p, "Probably too slow (7)", 7); obs_property_list_add_int(p, "Okay (8)", 8); obs_property_list_add_int(p, "Fast (9)", 9); @@ -307,13 +346,13 @@ obs_properties_t *aom_av1_properties(void *unused) { UNUSED_PARAMETER(unused); - return av1_properties(false); + return av1_properties(AV1_ENCODER_TYPE_AOM); } obs_properties_t *svt_av1_properties(void *unused) { UNUSED_PARAMETER(unused); - return av1_properties(true); + return av1_properties(AV1_ENCODER_TYPE_SVT); } static bool av1_extra_data(void *data, uint8_t **extra_data, size_t *size)
View file
obs-studio-28.1.2.tar.xz/plugins/obs-ffmpeg/obs-ffmpeg-formats.h -> obs-studio-29.0.0.tar.xz/plugins/obs-ffmpeg/obs-ffmpeg-formats.h
Changed
@@ -1,6 +1,7 @@ #pragma once #include <libavcodec/avcodec.h> +#include <libavutil/pixdesc.h> static inline int64_t rescale_ts(int64_t val, AVCodecContext *context, AVRational new_base) @@ -47,11 +48,9 @@ return AV_PIX_FMT_YUVA422P; case VIDEO_FORMAT_YUVA: return AV_PIX_FMT_YUVA444P; - case VIDEO_FORMAT_YA2L: #if LIBAVUTIL_BUILD >= AV_VERSION_INT(56, 31, 100) + case VIDEO_FORMAT_YA2L: return AV_PIX_FMT_YUVA444P12LE; -#else - return AV_PIX_FMT_NONE; #endif case VIDEO_FORMAT_I010: return AV_PIX_FMT_YUV420P10LE; @@ -59,11 +58,41 @@ return AV_PIX_FMT_P010LE; case VIDEO_FORMAT_NONE: case VIDEO_FORMAT_AYUV: - /* not supported by FFmpeg */ + default: return AV_PIX_FMT_NONE; } +} + +static enum AVChromaLocation +determine_chroma_location(enum AVPixelFormat pix_fmt, + enum AVColorSpace colorspace) +{ + const AVPixFmtDescriptor *const desc = av_pix_fmt_desc_get(pix_fmt); + if (desc) { + const unsigned log_chroma_w = desc->log2_chroma_w; + const unsigned log_chroma_h = desc->log2_chroma_h; + switch (log_chroma_h) { + case 0: + switch (log_chroma_w) { + case 0: + /* 4:4:4 */ + return AVCHROMA_LOC_CENTER; + case 1: + /* 4:2:2 */ + return AVCHROMA_LOC_LEFT; + } + break; + case 1: + if (log_chroma_w == 1) { + /* 4:2:0 */ + return (colorspace == AVCOL_SPC_BT2020_NCL) + ? AVCHROMA_LOC_TOPLEFT + : AVCHROMA_LOC_LEFT; + } + } + } - return AV_PIX_FMT_NONE; + return AVCHROMA_LOC_UNSPECIFIED; } static inline enum audio_format
View file
obs-studio-28.1.2.tar.xz/plugins/obs-ffmpeg/obs-ffmpeg-mpegts.c -> obs-studio-29.0.0.tar.xz/plugins/obs-ffmpeg/obs-ffmpeg-mpegts.c
Changed
@@ -31,8 +31,8 @@ #include <libavutil/mastering_display_metadata.h> /* ------------------------------------------------------------------------- */ -#define do_log(level, format, ...) \ - blog(level, "obs-ffmpeg mpegts muxer: '%s' " format, \ +#define do_log(level, format, ...) \ + blog(level, "obs-ffmpeg mpegts muxer: '%s': " format, \ obs_output_get_name(stream->output), ##__VA_ARGS__) #define warn(format, ...) do_log(LOG_WARNING, format, ##__VA_ARGS__) @@ -151,7 +151,7 @@ const char *name = data->config.video_encoder; const AVCodecDescriptor *codec = avcodec_descriptor_get_by_name(name); if (!codec) { - error("Couldn't find codec '%s'\n", name); + error("Couldn't find codec '%s'", name); return false; } if (!new_stream(data, &data->video, name)) @@ -206,10 +206,8 @@ context->color_primaries = data->config.color_primaries; context->color_trc = data->config.color_trc; context->colorspace = data->config.colorspace; - context->chroma_sample_location = - (data->config.colorspace == AVCOL_SPC_BT2020_NCL) - ? AVCHROMA_LOC_TOPLEFT - : AVCHROMA_LOC_LEFT; + context->chroma_sample_location = determine_chroma_location( + data->config.format, data->config.colorspace); context->thread_count = 0; data->video->time_base = context->time_base; @@ -235,10 +233,11 @@ void *extradata = NULL; struct obs_audio_info aoi; const char *name = data->config.audio_encoder; + int channels; const AVCodecDescriptor *codec = avcodec_descriptor_get_by_name(name); if (!codec) { - warn("Couldn't find codec '%s'\n", name); + warn("Couldn't find codec '%s'", name); return false; } @@ -255,14 +254,24 @@ context->codec_id = codec->id; context->bit_rate = (int64_t)data->config.audio_bitrate * 1000; context->time_base = (AVRational){1, aoi.samples_per_sec}; + channels = get_audio_channels(aoi.speakers); +#if LIBAVUTIL_VERSION_INT < AV_VERSION_INT(57, 24, 100) context->channels = get_audio_channels(aoi.speakers); +#endif context->sample_rate = aoi.samples_per_sec; + +#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(59, 24, 100) context->channel_layout = av_get_default_channel_layout(context->channels); //avutil default channel layout for 5 channels is 5.0 ; fix for 4.1 if (aoi.speakers == SPEAKERS_4POINT1) context->channel_layout = av_get_channel_layout("4.1"); +#else + av_channel_layout_default(&context->ch_layout, channels); + if (aoi.speakers == SPEAKERS_4POINT1) + context->ch_layout = (AVChannelLayout)AV_CHANNEL_LAYOUT_4POINT1; +#endif context->sample_fmt = AV_SAMPLE_FMT_S16; context->frame_size = data->config.frame_size; @@ -316,14 +325,14 @@ const char *url = stream->ff_data.config.url; if (!ff_network_init()) { ffmpeg_mpegts_log_error(LOG_ERROR, &stream->ff_data, - "Can not initialize network."); + "Couldn't initialize network"); return AVERROR(EIO); } URLContext *uc = av_mallocz(sizeof(URLContext) + strlen(url) + 1); if (!uc) { ffmpeg_mpegts_log_error(LOG_ERROR, &stream->ff_data, - "Can not allocate memory."); + "Couldn't allocate memory"); goto fail; } uc->url = (char *)url; @@ -333,14 +342,53 @@ : av_mallocz(sizeof(SRTContext)); if (!uc->priv_data) { ffmpeg_mpegts_log_error(LOG_ERROR, &stream->ff_data, - "Can not allocate memory."); + "Couldn't allocate memory"); goto fail; } + /* For SRT, pass streamid & passphrase; for RIST, pass passphrase, username + * & password. + */ + if (!is_rist) { + SRTContext *context = (SRTContext *)uc->priv_data; + context->streamid = NULL; + if (stream->ff_data.config.key != NULL) { + if (strlen(stream->ff_data.config.key)) + context->streamid = + av_strdup(stream->ff_data.config.key); + } + context->passphrase = NULL; + if (stream->ff_data.config.password != NULL) { + if (strlen(stream->ff_data.config.password)) + context->passphrase = av_strdup( + stream->ff_data.config.password); + } + } else { + RISTContext *context = (RISTContext *)uc->priv_data; + context->secret = NULL; + if (stream->ff_data.config.key != NULL) { + if (strlen(stream->ff_data.config.key)) + context->secret = + bstrdup(stream->ff_data.config.key); + } + context->username = NULL; + if (stream->ff_data.config.username != NULL) { + if (strlen(stream->ff_data.config.username)) + context->username = bstrdup( + stream->ff_data.config.username); + } + context->password = NULL; + if (stream->ff_data.config.password != NULL) { + if (strlen(stream->ff_data.config.password)) + context->password = bstrdup( + stream->ff_data.config.password); + } + } stream->h = uc; if (is_rist) err = librist_open(uc, uc->url); else err = libsrt_open(uc, uc->url); + if (err < 0) goto fail; return 0; @@ -408,9 +456,9 @@ "=", " ", 0))) { ffmpeg_mpegts_log_error( LOG_WARNING, data, - "Failed to parse protocol settings: %s\n%s", - av_err2str(ret), - data->config.protocol_settings); + "Failed to parse protocol settings: %s, %s", + data->config.protocol_settings, + av_err2str(ret)); av_dict_free(&dict); return OBS_OUTPUT_INVALID_STREAM; @@ -444,7 +492,7 @@ ret = avio_open2(&data->output->pb, data->config.url, AVIO_FLAG_WRITE, NULL, &dict); } else { - info("ffmpeg mpegts muxer: Invalid protocol: %s", + info("ffmpeg mpegts muxer: Invalid protocol: %s", data->config.url); return OBS_OUTPUT_BAD_PATH; } @@ -452,7 +500,7 @@ if (ret < 0) { if ((rist || srt) && (ret == OBS_OUTPUT_CONNECT_FAILED || ret == OBS_OUTPUT_INVALID_STREAM)) { - error("failed to open the url or invalid stream"); + error("Failed to open the url or invalid stream"); } else { ffmpeg_mpegts_log_error(LOG_WARNING, data, "Couldn't open '%s', %s", @@ -477,7 +525,7 @@ dstr_catf(&str, "\n\t%s=%s", entry->key, entry->value); - info("ffmpeg mpegts muxer:Invalid protocol settings: %s", + info("ffmpeg mpegts muxer: Invalid protocol settings: %s", str.array); dstr_free(&str); } @@ -485,7 +533,7 @@ } else { ret = allocate_custom_aviocontext(stream, rist); if (ret < 0) { - info("Couldn't allocate custom avio_context for rist or srt'%s', %s\n", + info("Couldn't allocate custom avio_context for url: '%s', %s", data->config.url, av_err2str(ret)); return OBS_OUTPUT_INVALID_STREAM; } @@ -541,7 +589,7 @@ avio_context_free(&stream->s); if (err) - info("ffmpeg mpegts muxer: Error closing URL %s", + info("ffmpeg mpegts muxer: Error closing URL %s", stream->ff_data.config.url); } @@ -615,7 +663,7 @@ "Couldn't set output format to mpegts"); goto fail; } else { - info("info: Output format name and long_name: %s, %s\n", + info("Output format name and long_name: %s, %s", output_format->name ? output_format->name : "unknown", output_format->long_name ? output_format->long_name : "unknown"); @@ -828,13 +876,15 @@ int ret; int code; - /* 1. Get URL from service & set format + mime-type. */ + /* 1. Get URL/username/password from service & set format + mime-type. */ obs_service_t *service; service = obs_output_get_service(stream->output); if (!service) return false; config.url = obs_service_get_url(service); - + config.username = obs_service_get_username(service); + config.password = obs_service_get_password(service); + config.key = obs_service_get_key(service); config.format_name = "mpegts"; config.format_mime_type = "video/M2PT"; @@ -845,7 +895,8 @@ obs_to_ffmpeg_video_format(video_output_get_format(video)); if (config.format == AV_PIX_FMT_NONE) { - blog(LOG_DEBUG, "invalid pixel format used for mpegts output"); + blog(LOG_WARNING, + "Invalid pixel format used for mpegts output"); return false; } @@ -960,7 +1011,7 @@ } code = open_output_file(stream, ff_data); if (code != 0) { - error("failed to open the url"); + error("Failed to open the url"); goto fail; } av_dump_format(ff_data->output, 0, NULL, 1); @@ -974,7 +1025,7 @@ if (ret != 0) { ffmpeg_mpegts_log_error( LOG_WARNING, &stream->ff_data, - "ffmpeg_output_start: failed to create write " + "ffmpeg_output_start: Failed to create write " "thread."); code = OBS_OUTPUT_ERROR; goto fail; @@ -1104,7 +1155,7 @@ packet->data = av_memdup(encpacket->data, (int)encpacket->size); if (packet->data == NULL) { - error("couldn't allocate packet data"); + error("Couldn't allocate packet data"); goto fail; } packet->size = (int)encpacket->size; @@ -1132,8 +1183,8 @@ " ", 0))) { ffmpeg_mpegts_log_error( LOG_WARNING, data, - "Failed to parse muxer settings: %s\n%s", - av_err2str(ret), data->config.muxer_settings); + "Failed to parse muxer settings: %s, %s", + data->config.muxer_settings, av_err2str(ret)); av_dict_free(&dict); return false; @@ -1170,7 +1221,7 @@ AV_DICT_IGNORE_SUFFIX))) dstr_catf(&str, "\n\t%s=%s", entry->key, entry->value); - info("ffmpeg mpegts muxer: Invalid mpegts muxer settings: %s", + info("ffmpeg mpegts muxer: Invalid mpegts muxer settings: %s", str.array); dstr_free(&str); } @@ -1188,12 +1239,12 @@ if (get_extradata(stream)) { stream->got_headers = true; } else { - warn("failed to retrieve headers"); + warn("Failed to retrieve headers"); code = OBS_OUTPUT_INVALID_STREAM; goto fail; } if (!write_header(stream, ff_data)) { - error("failed to write headers"); + error("Failed to write headers"); code = OBS_OUTPUT_INVALID_STREAM; goto fail; }
View file
obs-studio-28.1.2.tar.xz/plugins/obs-ffmpeg/obs-ffmpeg-mux.c -> obs-studio-29.0.0.tar.xz/plugins/obs-ffmpeg/obs-ffmpeg-mux.c
Changed
@@ -16,6 +16,7 @@ ******************************************************************************/ #include "ffmpeg-mux/ffmpeg-mux.h" #include "obs-ffmpeg-mux.h" +#include "obs-ffmpeg-formats.h" #ifdef _WIN32 #include "util/windows/win-version.h" @@ -142,6 +143,14 @@ video_t *video = obs_get_video(); const struct video_output_info *info = video_output_get_info(video); + int codec_tag = (int)obs_data_get_int(settings, "codec_type"); +#if __BYTE_ORDER == __LITTLE_ENDIAN + codec_tag = ((codec_tag >> 24) & 0x000000FF) | + ((codec_tag << 8) & 0x00FF0000) | + ((codec_tag >> 8) & 0x0000FF00) | + ((codec_tag << 24) & 0xFF000000); +#endif + obs_data_release(settings); enum AVColorPrimaries pri = AVCOL_PRI_UNSPECIFIED; @@ -184,12 +193,15 @@ ? (int)obs_get_video_hdr_nominal_peak_level() : ((trc == AVCOL_TRC_ARIB_STD_B67) ? 1000 : 0); - dstr_catf(cmd, "%s %d %d %d %d %d %d %d %d %d %d ", + dstr_catf(cmd, "%s %d %d %d %d %d %d %d %d %d %d %d %d ", obs_encoder_get_codec(vencoder), bitrate, obs_output_get_width(stream->output), obs_output_get_height(stream->output), (int)pri, (int)trc, - (int)spc, (int)range, max_luminance, (int)info->fps_num, - (int)info->fps_den); + (int)spc, (int)range, + (int)determine_chroma_location( + obs_to_ffmpeg_video_format(info->format), spc), + max_luminance, (int)info->fps_num, (int)info->fps_den, + (int)codec_tag); } static void add_audio_encoder_params(struct dstr *cmd, obs_encoder_t *aencoder)
View file
obs-studio-28.1.2.tar.xz/plugins/obs-ffmpeg/obs-ffmpeg-nvenc.c -> obs-studio-29.0.0.tar.xz/plugins/obs-ffmpeg/obs-ffmpeg-nvenc.c
Changed
@@ -428,7 +428,7 @@ obs_data_set_default_int(settings, "keyint_sec", 0); obs_data_set_default_int(settings, "cqp", 20); obs_data_set_default_string(settings, "rate_control", "CBR"); - obs_data_set_default_string(settings, "preset2", "p6"); + obs_data_set_default_string(settings, "preset2", "p5"); obs_data_set_default_string(settings, "multipass", "qres"); obs_data_set_default_string(settings, "tune", "hq"); obs_data_set_default_string(settings, "profile",
View file
obs-studio-28.1.2.tar.xz/plugins/obs-ffmpeg/obs-ffmpeg-output.c -> obs-studio-29.0.0.tar.xz/plugins/obs-ffmpeg/obs-ffmpeg-output.c
Changed
@@ -152,10 +152,8 @@ data->vframe->color_primaries = data->config.color_primaries; data->vframe->color_trc = data->config.color_trc; data->vframe->colorspace = data->config.colorspace; - data->vframe->chroma_location = - (data->config.colorspace == AVCOL_SPC_BT2020_NCL) - ? AVCHROMA_LOC_TOPLEFT - : AVCHROMA_LOC_LEFT; + data->vframe->chroma_location = determine_chroma_location( + context->pix_fmt, data->config.colorspace); ret = av_frame_get_buffer(data->vframe, base_get_alignment()); if (ret < 0) { @@ -262,10 +260,8 @@ context->color_primaries = data->config.color_primaries; context->color_trc = data->config.color_trc; context->colorspace = data->config.colorspace; - context->chroma_sample_location = - (data->config.colorspace == AVCOL_SPC_BT2020_NCL) - ? AVCHROMA_LOC_TOPLEFT - : AVCHROMA_LOC_LEFT; + context->chroma_sample_location = determine_chroma_location( + closest_format, data->config.colorspace); context->thread_count = 0; data->video->time_base = context->time_base; @@ -294,6 +290,7 @@ AVCodecContext *const context = data->audio_infosidx.ctx; char **opts = strlist_split(data->config.audio_settings, ' ', false); int ret; + int channels; if (opts) { parse_params(context, opts); @@ -308,11 +305,13 @@ } data->aframeidx->format = context->sample_fmt; - data->aframeidx->channels = context->channels; #if LIBAVUTIL_VERSION_INT < AV_VERSION_INT(57, 24, 100) + data->aframeidx->channels = context->channels; data->aframeidx->channel_layout = context->channel_layout; + channels = context->channels; #else data->aframeidx->ch_layout = context->ch_layout; + channels = context->ch_layout.nb_channels; #endif data->aframeidx->sample_rate = context->sample_rate; context->strict_std_compliance = -2; @@ -327,7 +326,7 @@ data->frame_size = context->frame_size ? context->frame_size : 1024; - ret = av_samples_alloc(data->samplesidx, NULL, context->channels, + ret = av_samples_alloc(data->samplesidx, NULL, channels, data->frame_size, context->sample_fmt, 0); if (ret < 0) { ffmpeg_log_error(LOG_WARNING, data, @@ -349,6 +348,7 @@ AVCodecContext *context; AVStream *stream; struct obs_audio_info aoi; + int channels; if (!obs_get_audio_info(&aoi)) { ffmpeg_log_error(LOG_WARNING, data, "No active audio"); @@ -367,17 +367,20 @@ #endif context->bit_rate = (int64_t)data->config.audio_bitrate * 1000; context->time_base = (AVRational){1, aoi.samples_per_sec}; +#if LIBAVUTIL_VERSION_INT < AV_VERSION_INT(57, 24, 100) context->channels = get_audio_channels(aoi.speakers); +#endif + channels = get_audio_channels(aoi.speakers); + context->sample_rate = aoi.samples_per_sec; #if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(59, 24, 100) - context->channel_layout = - av_get_default_channel_layout(context->channels); + context->channel_layout = av_get_default_channel_layout(channels); //avutil default channel layout for 5 channels is 5.0 ; fix for 4.1 if (aoi.speakers == SPEAKERS_4POINT1) context->channel_layout = av_get_channel_layout("4.1"); #else - av_channel_layout_default(&context->ch_layout, context->channels); + av_channel_layout_default(&context->ch_layout, channels); if (aoi.speakers == SPEAKERS_4POINT1) context->ch_layout = (AVChannelLayout)AV_CHANNEL_LAYOUT_4POINT1; #endif @@ -865,14 +868,20 @@ AVPacket *packet = NULL; int ret, got_packet; - size_t total_size = data->frame_size * block_size * context->channels; + int channels; +#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(57, 24, 100) + channels = context->ch_layout.nb_channels; +#else + channels = context->channels; +#endif + size_t total_size = data->frame_size * block_size * channels; data->aframeidx->nb_samples = data->frame_size; data->aframeidx->pts = av_rescale_q( data->total_samplesidx, (AVRational){1, context->sample_rate}, context->time_base); - ret = avcodec_fill_audio_frame(data->aframeidx, context->channels, + ret = avcodec_fill_audio_frame(data->aframeidx, channels, context->sample_fmt, data->samplesidx0, (int)total_size, 1);
View file
obs-studio-28.1.2.tar.xz/plugins/obs-ffmpeg/obs-ffmpeg-output.h -> obs-studio-29.0.0.tar.xz/plugins/obs-ffmpeg/obs-ffmpeg-output.h
Changed
@@ -37,6 +37,9 @@ int width; int height; int frame_size; // audio frame size + const char *username; + const char *password; + const char *key; }; struct ffmpeg_audio_info {
View file
obs-studio-28.1.2.tar.xz/plugins/obs-ffmpeg/obs-ffmpeg-rist.h -> obs-studio-29.0.0.tar.xz/plugins/obs-ffmpeg/obs-ffmpeg-rist.h
Changed
@@ -44,7 +44,8 @@ int fifo_shift; bool overrun_nonfatal; char *secret; - + char *username; + char *password; struct rist_logging_settings logging_settings; struct rist_peer_config peer_config; @@ -100,14 +101,19 @@ { RISTContext *s = h->priv_data; int ret = 0; - + if (s->secret) + bfree(s->secret); + if (s->username) + bfree(s->username); + if (s->password) + bfree(s->password); s->peer = NULL; if (s->ctx) ret = rist_destroy(s->ctx); if (ret < 0) { blog(LOG_ERROR, - "obs-ffmpeg mpegts muxer / librist : failed to close properly %s\n", + "obs-ffmpeg mpegts muxer / librist: Failed to close properly %s", h->url); return -1; } @@ -122,11 +128,15 @@ rist_log(&s->logging_settings, RIST_LOG_INFO, "%s\n", stats_container->stats_json); if (stats_container->stats_type == RIST_STATS_SENDER_PEER) { + blog(LOG_INFO, "---------------------------------"); blog(LOG_DEBUG, - "obs-ffmpeg mpegts muxer / librist RIST STATS\n\n" - "bandwidth %.3f Mbps\npackets sent %llu\npkts received %llu\n" - "pkts retransmitted %llu\nquality (pkt sent over sent+retransmitted+skipped) %.2f \n" - "rtt %" PRIu32 " ms\n\n", + "obs-ffmpeg mpegts muxer / librist: Session Summary\n" + "\tbandwidth %.3f Mbps\n" + "\tpackets sent %lu\n" + "\tpkts received %lu\n" + "\tpkts retransmitted %lu\n" + "\tquality (pkt sent over sent+retransmitted+skipped) %.2f\n" + "\trtt %" PRIu32 " ms\n", (double)(stats_container->stats.sender_peer.bandwidth) / 1000000.0, stats_container->stats.sender_peer.sent, @@ -150,7 +160,6 @@ s->packet_size = 1316; s->log_level = RIST_LOG_INFO; s->encryption = 0; - s->secret = NULL; s->overrun_nonfatal = 0; s->fifo_shift = FF_LIBRIST_FIFO_DEFAULT_SHIFT; s->logging_settings = @@ -161,12 +170,12 @@ NULL); if (ret < 0) { blog(LOG_ERROR, - "obs-ffmpeg mpegts muxer / librist : Failed to initialize logging settings."); + "obs-ffmpeg mpegts muxer / librist: Failed to initialize logging settings"); return OBS_OUTPUT_CONNECT_FAILED; } blog(LOG_INFO, - "obs-ffmpeg mpegts muxer / librist : \n librist version %s & API = %s .", + "obs-ffmpeg mpegts muxer / librist: libRIST version: %s, API: %s", librist_version(), librist_api_version()); h->max_packet_size = s->packet_size; @@ -174,14 +183,14 @@ if (ret < 0) { blog(LOG_ERROR, - "obs-ffmpeg mpegts muxer / librist : failed to create a sender \n"); + "obs-ffmpeg mpegts muxer / librist: Failed to create a sender"); goto err; } ret = rist_peer_config_defaults_set(peer_config); if (ret < 0) { blog(LOG_ERROR, - "obs-ffmpeg mpegts muxer / librist : failed to set peer config defaults.\n"); + "obs-ffmpeg mpegts muxer / librist: Failed to set peer config defaults"); goto err; } @@ -193,7 +202,7 @@ #endif if (ret < 0) { blog(LOG_ERROR, - "obs-ffmpeg mpegts muxer / librist : failed to parse the url %s\n", + "obs-ffmpeg mpegts muxer / librist: Failed to parse url: %s", uri); librist_close(h); return OBS_OUTPUT_INVALID_STREAM; @@ -203,7 +212,7 @@ ((peer_config->key_size == 128 || peer_config->key_size == 256) && !peer_config->secret0)) { blog(LOG_ERROR, - "secret is mandatory if encryption is enabled\n"); + "obs-ffmpeg mpegts muxer / librist: Secret is mandatory if encryption is enabled"); librist_close(h); return OBS_OUTPUT_INVALID_STREAM; } @@ -219,26 +228,30 @@ peer_config->recovery_length_min = s->buffer_size; peer_config->recovery_length_max = s->buffer_size; } + if (s->username && peer_config->srp_username0 == 0) + av_strlcpy(peer_config->srp_username, s->username, + RIST_MAX_STRING_LONG); + if (s->password && peer_config->srp_password0 == 0) + av_strlcpy(peer_config->srp_password, s->password, + RIST_MAX_STRING_LONG); ret = rist_peer_create(s->ctx, &s->peer, &s->peer_config); if (ret < 0) { blog(LOG_ERROR, - "obs-ffmpeg mpegts muxer / librist : failed to create a peer. \n"); + "obs-ffmpeg mpegts muxer / librist: Failed to create a peer."); goto err; } ret = rist_start(s->ctx); if (ret < 0) { blog(LOG_ERROR, - "obs-ffmpeg mpegts muxer / librist : rist failed to start \n"); + "obs-ffmpeg mpegts muxer / librist: RIST failed to start"); goto err; } if (rist_stats_callback_set(s->ctx, s->statsinterval, cb_stats, - (void *)s) == -1) { + (void *)s) == -1) rist_log(&s->logging_settings, RIST_LOG_ERROR, - "Could not enable stats callback\n"); - ; - } + "Could not enable stats callback"); return 0; err: @@ -260,7 +273,7 @@ ret = rist_sender_data_write(s->ctx, &data_block); if (ret < 0) { blog(LOG_WARNING, - "obs-ffmpeg mpegts muxer / librist : failed to send data of size %i bytes", + "obs-ffmpeg mpegts muxer / librist: Failed to send %i bytes", size); return risterr2ret(ret); }
View file
obs-studio-28.1.2.tar.xz/plugins/obs-ffmpeg/obs-ffmpeg-srt.h -> obs-studio-29.0.0.tar.xz/plugins/obs-ffmpeg/obs-ffmpeg-srt.h
Changed
@@ -80,12 +80,24 @@ static int libsrt_neterrno(URLContext *h) { + SRTContext *s = (SRTContext *)h->priv_data; int os_errno; int err = srt_getlasterror(&os_errno); - blog(LOG_ERROR, "obs-ffmpeg mpegts muxer / libsrt : %s\n", + blog(LOG_ERROR, "obs-ffmpeg mpegts muxer / libsrt: %s", srt_getlasterror_str()); if (err == SRT_EASYNCRCV || err == SRT_EASYNCSND) return AVERROR(EAGAIN); + if (err == SRT_ECONNREJ) { + int errj = srt_getrejectreason(s->fd); + if (errj == SRT_REJ_BADSECRET) + blog(LOG_ERROR, + "obs-ffmpeg mpegts muxer / libsrt: Wrong password"); + else + blog(LOG_ERROR, + "obs-ffmpeg mpegts muxer / libsrt: Connection rejected, %s", + srt_rejectreason_str(errj)); + } + return os_errno ? AVERROR(os_errno) : AVERROR_UNKNOWN; } @@ -94,7 +106,7 @@ { if (srt_getsockopt(fd, 0, optname, optval, optlen) < 0) { blog(LOG_INFO, - "obs-ffmpeg mpegts muxer / libsrt : failed to get option %s on socket: %s\n", + "obs-ffmpeg mpegts muxer / libsrt: Failed to get option %s on socket: %s", optnamestr, srt_getlasterror_str()); return AVERROR(EIO); } @@ -139,6 +151,21 @@ ret = srt_epoll_wait(eid, ready, &len, error, &errlen, POLLING_TIME, 0, 0, 0, 0); } + if (len == 1 && errlen == 1) { + /* Socket reported in wsock AND rsock signifies an error. */ + int reason = srt_getrejectreason(*ready); + + if (reason == SRT_REJ_BADSECRET || reason == SRT_REJ_UNSECURE || + reason == SRT_REJ_TIMEOUT) { + blog(LOG_ERROR, + "obs-ffmpeg mpegts muxer / libsrt: Connection rejected, wrong password or invalid URL"); + return OBS_OUTPUT_INVALID_STREAM; + } else { + blog(LOG_ERROR, + "obs-ffmpeg mpegts muxer / libsrt: Connection rejected, %s", + srt_rejectreason_str(reason)); + } + } if (ret < 0) { if (srt_getlasterror(NULL) == SRT_ETIMEOUT) ret = AVERROR(EAGAIN); @@ -190,7 +217,7 @@ if (srt_setsockopt(fd, SOL_SOCKET, SRTO_REUSEADDR, &reuse, sizeof(reuse))) { blog(LOG_WARNING, - "obs-ffmpeg mpegts muxer / libsrt : setsockopt(SRTO_REUSEADDR) failed\n"); + "obs-ffmpeg mpegts muxer / libsrt: setsockopt(SRTO_REUSEADDR) failed"); } if (srt_bind(fd, addr, addrlen)) return libsrt_neterrno(h); @@ -208,12 +235,12 @@ return libsrt_neterrno(h); if (libsrt_socket_nonblock(ret, 1) < 0) blog(LOG_DEBUG, - "obs-ffmpeg mpegts muxer / libsrt : libsrt_socket_nonblock failed\n"); + "obs-ffmpeg mpegts muxer / libsrt: libsrt_socket_nonblock failed"); if (!libsrt_getsockopt(h, ret, SRTO_STREAMID, "SRTO_STREAMID", streamid, &streamid_len)) /* Note: returned streamid_len doesn't count the terminating null character */ blog(LOG_INFO, - "obs-ffmpeg mpegts muxer / libsrt : accept streamid %s, length %d\n", + "obs-ffmpeg mpegts muxer / libsrt: Accept streamid %s, length %d", streamid, streamid_len); return ret; @@ -233,11 +260,11 @@ if (ret < 0) { if (will_try_next) { blog(LOG_WARNING, - "obs-ffmpeg mpegts muxer / libsrt : Connection to %s failed (%s), trying next address\n", + "obs-ffmpeg mpegts muxer / libsrt: Connection to %s failed (%s), trying next address", h->url, av_err2str(ret)); } else { blog(LOG_ERROR, - "obs-ffmpeg mpegts muxer / libsrt : Connection to %s failed: %s\n", + "obs-ffmpeg mpegts muxer / libsrt: Connection to %s failed: %s", h->url, av_err2str(ret)); } } @@ -250,7 +277,7 @@ { if (srt_setsockopt(fd, 0, optname, optval, optlen) < 0) { blog(LOG_ERROR, - "obs-ffmpeg mpegts muxer / libsrt : failed to set option %s on socket: %s\n", + "obs-ffmpeg mpegts muxer / libsrt: Failed to set option %s on socket: %s", optnamestr, srt_getlasterror_str()); return AVERROR(EIO); } @@ -434,7 +461,7 @@ return AVERROR(EINVAL); if (port <= 0 || port >= 65536) { blog(LOG_ERROR, - "obs-ffmpeg mpegts muxer / libsrt : Port missing in uri\n"); + "obs-ffmpeg mpegts muxer / libsrt: Port missing in uri"); return OBS_OUTPUT_CONNECT_FAILED; } p = strchr(uri, '?'); @@ -457,7 +484,7 @@ ret = getaddrinfo(hostname0 ? hostname : NULL, portstr, &hints, &ai); if (ret) { blog(LOG_ERROR, - "obs-ffmpeg mpegts muxer / libsrt : Failed to resolve hostname %s: %s\n", + "obs-ffmpeg mpegts muxer / libsrt: Failed to resolve hostname %s: %s", hostname, gai_strerror(ret)); return OBS_OUTPUT_CONNECT_FAILED; } @@ -490,7 +517,7 @@ } if (libsrt_socket_nonblock(fd, 1) < 0) blog(LOG_DEBUG, - "obs-ffmpeg mpegts muxer / libsrt : libsrt_socket_nonblock failed\n"); + "obs-ffmpeg mpegts muxer / libsrt: libsrt_socket_nonblock failed"); ret = write_eid = libsrt_epoll_create(h, fd, 1); if (ret < 0) @@ -574,7 +601,6 @@ s->payload_size = SRT_LIVE_DEFAULT_PAYLOAD_SIZE; s->maxbw = -1; s->pbkeylen = -1; - s->passphrase = NULL; s->mss = -1; s->ffs = -1; s->ipttl = -1; @@ -592,7 +618,6 @@ s->rcvbuf = -1; s->lossmaxttl = -1; s->minversion = -1; - s->streamid = NULL; s->smoother = NULL; s->messageapi = -1; s->transtype = SRTT_LIVE; @@ -609,11 +634,11 @@ if (srt_startup() < 0) { blog(LOG_ERROR, - "obs-ffmpeg mpegts muxer / libsrt : libsrt failed to load.\n"); + "obs-ffmpeg mpegts muxer / libsrt: libsrt failed to load"); return OBS_OUTPUT_CONNECT_FAILED; } else { blog(LOG_INFO, - "obs-ffmpeg mpegts muxer / libsrt : libsrt v.%s loaded.\n", + "obs-ffmpeg mpegts muxer / libsrt: libsrt version %s loaded", SRT_VERSION_STRING); } libsrt_set_defaults(s); @@ -801,8 +826,8 @@ #endif if (time > (s->time + 60.0)) { srt_bistats(s->fd, &perf, 0, 1); - blog(LOG_INFO, - "obs-ffmpeg mpegts muxer / libsrt : rtt %.2f ms, link bandwidth %.1f Mbps\n", + blog(LOG_DEBUG, + "obs-ffmpeg mpegts muxer / libsrt: RTT %.2f ms, Link Bandwidth %.1f Mbps", perf.msRTT, perf.mbpsBandwidth); s->time = time; } @@ -814,15 +839,21 @@ static int libsrt_close(URLContext *h) { SRTContext *s = (SRTContext *)h->priv_data; - + if (s->streamid) + av_freep(&s->streamid); + if (s->passphrase) + av_freep(&s->passphrase); /* Log stream stats. */ SRT_TRACEBSTATS perf; srt_bstats(s->fd, &perf, 1); + blog(LOG_INFO, "---------------------------------"); blog(LOG_INFO, - "obs-ffmpeg mpegts muxer / libsrt : Stream stats\n\n" - "time elapsed %.1f sec\nmean speed %.1f Mbp\n" - "total bytes sent %.1f MB\nbytes retransmitted %.1f %%\n" - "bytes dropped %.1f %%\n\n", + "obs-ffmpeg mpegts muxer / libsrt: Session Summary\n" + "\ttime elapsed %.1f sec\n" + "\tmean speed %.1f Mbp\n" + "\ttotal bytes sent %.1f MB\n" + "\tbytes retransmitted %.1f %%\n" + "\tbytes dropped %.1f %%\n", (double)perf.msTimeStamp / 1000.0, perf.mbpsSendRate, (double)perf.byteSentTotal / 1000000.0, perf.byteSentTotal @@ -835,13 +866,14 @@ srt_epoll_release(s->eid); int err = srt_close(s->fd); if (err < 0) { - blog(LOG_ERROR, "obs-ffmpeg mpegts muxer / libsrt : %s\n", + blog(LOG_ERROR, "obs-ffmpeg mpegts muxer / libsrt: %s", srt_getlasterror_str()); return -1; } srt_cleanup(); - blog(LOG_INFO, "obs-ffmpeg mpegts muxer / libsrt : closing srt"); + blog(LOG_INFO, + "obs-ffmpeg mpegts muxer / libsrt: SRT connection closed"); return 0; }
View file
obs-studio-28.1.2.tar.xz/plugins/obs-ffmpeg/obs-ffmpeg-vaapi.c -> obs-studio-29.0.0.tar.xz/plugins/obs-ffmpeg/obs-ffmpeg-vaapi.c
Changed
@@ -38,10 +38,11 @@ #include <pci/pci.h> +#include "vaapi-utils.h" #include "obs-ffmpeg-formats.h" #define do_log(level, format, ...) \ - blog(level, "FFMPEG VAAPI encoder: '%s' " format, \ + blog(level, "FFmpeg VAAPI encoder: '%s' " format, \ obs_encoder_get_name(enc->encoder), ##__VA_ARGS__) #define warn(format, ...) do_log(LOG_WARNING, format, ##__VA_ARGS__) @@ -77,7 +78,7 @@ static const char *vaapi_getname(void *unused) { UNUSED_PARAMETER(unused); - return "FFMPEG VAAPI H.264"; + return "FFmpeg VAAPI H.264"; } static inline bool valid_format(enum video_format format) @@ -144,6 +145,7 @@ enc->vframe->height = enc->context->height; enc->vframe->colorspace = enc->context->colorspace; enc->vframe->color_range = enc->context->color_range; + enc->vframe->chroma_location = enc->context->chroma_sample_location; ret = av_frame_get_buffer(enc->vframe, base_get_alignment()); if (ret < 0) { @@ -250,30 +252,37 @@ enc->context->height = obs_encoder_get_height(enc->encoder); enc->context->time_base = (AVRational){voi->fps_den, voi->fps_num}; - enc->context->pix_fmt = obs_to_ffmpeg_video_format(info.format); + const enum AVPixelFormat pix_fmt = + obs_to_ffmpeg_video_format(info.format); + enc->context->pix_fmt = pix_fmt; enc->context->color_range = info.range == VIDEO_RANGE_FULL ? AVCOL_RANGE_JPEG : AVCOL_RANGE_MPEG; + enum AVColorSpace colorspace = AVCOL_SPC_UNSPECIFIED; switch (info.colorspace) { case VIDEO_CS_601: enc->context->color_trc = AVCOL_TRC_SMPTE170M; enc->context->color_primaries = AVCOL_PRI_SMPTE170M; - enc->context->colorspace = AVCOL_SPC_SMPTE170M; + colorspace = AVCOL_SPC_SMPTE170M; break; case VIDEO_CS_DEFAULT: case VIDEO_CS_709: enc->context->color_trc = AVCOL_TRC_BT709; enc->context->color_primaries = AVCOL_PRI_BT709; - enc->context->colorspace = AVCOL_SPC_BT709; + colorspace = AVCOL_SPC_BT709; break; case VIDEO_CS_SRGB: enc->context->color_trc = AVCOL_TRC_IEC61966_2_1; enc->context->color_primaries = AVCOL_PRI_BT709; - enc->context->colorspace = AVCOL_SPC_BT709; + colorspace = AVCOL_SPC_BT709; break; } + enc->context->colorspace = colorspace; + enc->context->chroma_sample_location = + determine_chroma_location(pix_fmt, colorspace); + if (keyint_sec > 0) { enc->context->gop_size = keyint_sec * voi->fps_num / voi->fps_den; @@ -511,8 +520,9 @@ static void vaapi_defaults(obs_data_t *settings) { - obs_data_set_default_string(settings, "vaapi_device", - "/dev/dri/renderD128"); + const char *device = vaapi_get_h264_default_device(); + + obs_data_set_default_string(settings, "vaapi_device", device); obs_data_set_default_int(settings, "profile", FF_PROFILE_H264_CONSTRAINED_BASELINE); obs_data_set_default_int(settings, "level", 40); @@ -520,9 +530,67 @@ obs_data_set_default_int(settings, "keyint_sec", 0); obs_data_set_default_int(settings, "bf", 0); obs_data_set_default_int(settings, "rendermode", 0); - obs_data_set_default_string(settings, "rate_control", "CBR"); obs_data_set_default_int(settings, "qp", 20); obs_data_set_default_int(settings, "maxrate", 0); + + int drm_fd = -1; + VADisplay va_dpy = vaapi_open_device(&drm_fd, device, "vaapi_defaults"); + if (!va_dpy) + return; + + if (vaapi_device_rc_supported(VAProfileH264ConstrainedBaseline, va_dpy, + VA_RC_CBR, device)) + obs_data_set_default_string(settings, "rate_control", "CBR"); + else if (vaapi_device_rc_supported(VAProfileH264ConstrainedBaseline, + va_dpy, VA_RC_VBR, device)) + obs_data_set_default_string(settings, "rate_control", "VBR"); + else + obs_data_set_default_string(settings, "rate_control", "CQP"); + + vaapi_close_device(&drm_fd, va_dpy); +} + +static bool vaapi_device_modified(obs_properties_t *ppts, obs_property_t *p, + obs_data_t *settings) +{ + UNUSED_PARAMETER(p); + + const char *device = obs_data_get_string(settings, "vaapi_device"); + int drm_fd = -1; + VADisplay va_dpy = + vaapi_open_device(&drm_fd, device, "vaapi_device_modified"); + int profile = obs_data_get_int(settings, "profile"); + obs_property_t *rc_p = obs_properties_get(ppts, "rate_control"); + + obs_property_list_clear(rc_p); + + if (!va_dpy || !vaapi_display_h264_supported(va_dpy, device)) + goto fail; + + switch (profile) { + case FF_PROFILE_H264_CONSTRAINED_BASELINE: + profile = VAProfileH264ConstrainedBaseline; + break; + case FF_PROFILE_H264_MAIN: + profile = VAProfileH264Main; + break; + case FF_PROFILE_H264_HIGH: + profile = VAProfileH264High; + break; + } + + if (vaapi_device_rc_supported(profile, va_dpy, VA_RC_CBR, device)) + obs_property_list_add_string(rc_p, "CBR (default)", "CBR"); + + if (vaapi_device_rc_supported(profile, va_dpy, VA_RC_VBR, device)) + obs_property_list_add_string(rc_p, "VBR", "VBR"); + + if (vaapi_device_rc_supported(profile, va_dpy, VA_RC_CQP, device)) + obs_property_list_add_string(rc_p, "CQP", "CQP"); + +fail: + vaapi_close_device(&drm_fd, va_dpy); + return true; } static bool rate_control_modified(obs_properties_t *ppts, obs_property_t *p, @@ -617,6 +685,10 @@ bool name_found = get_device_name_from_pci( pacc, pci_slot, namebuf, sizeof(namebuf)); + + if (!vaapi_device_h264_supported(path)) + continue; + if (!name_found) obs_property_list_add_string(list, path, path); @@ -629,12 +701,21 @@ os_closedir(by_path_dir); } if (obs_property_list_item_count(list) == 0) { - char path32 = "/dev/dri/renderD1"; + char path32; for (int i = 28;; i++) { - sprintf(path, "/dev/dri/renderD1%d", i); + snprintf(path, sizeof(path), "/dev/dri/renderD1%d", i); if (access(path, F_OK) == 0) { - char card128 = "Card: "; - sprintf(card, "Card%d: %s", i - 28, path); + char card128; + int ret = snprintf(card, sizeof(card), + "Card%d: %s", i - 28, path); + if (ret >= (int)sizeof(card)) + blog(LOG_DEBUG, + "obs-ffmpeg-vaapi: A format truncation may have occurred." + " This can be ignored since it is quite improbable."); + + if (!vaapi_device_h264_supported(path)) + continue; + obs_property_list_add_string(list, card, path); } else { break; @@ -642,6 +723,8 @@ } } + obs_property_set_modified_callback(list, vaapi_device_modified); + list = obs_properties_add_list(props, "profile", obs_module_text("Profile"), OBS_COMBO_TYPE_LIST, @@ -651,6 +734,8 @@ obs_property_list_add_int(list, "Main", FF_PROFILE_H264_MAIN); obs_property_list_add_int(list, "High", FF_PROFILE_H264_HIGH); + obs_property_set_modified_callback(list, vaapi_device_modified); + list = obs_properties_add_list(props, "level", obs_module_text("Level"), OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT); @@ -669,9 +754,6 @@ obs_module_text("RateControl"), OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_STRING); - obs_property_list_add_string(list, "CBR (default)", "CBR"); - obs_property_list_add_string(list, "CQP", "CQP"); - obs_property_list_add_string(list, "VBR", "VBR"); obs_property_set_modified_callback(list, rate_control_modified);
View file
obs-studio-28.1.2.tar.xz/plugins/obs-ffmpeg/obs-ffmpeg-video-encoders.c -> obs-studio-29.0.0.tar.xz/plugins/obs-ffmpeg/obs-ffmpeg-video-encoders.c
Changed
@@ -68,46 +68,51 @@ const char *ffmpeg_opts) { const int rate = bitrate * 1000; + const enum AVPixelFormat pix_fmt = + obs_to_ffmpeg_video_format(info->format); enc->context->bit_rate = rate; enc->context->rc_buffer_size = rate; enc->context->width = obs_encoder_get_width(enc->encoder); enc->context->height = obs_encoder_get_height(enc->encoder); enc->context->time_base = (AVRational){voi->fps_den, voi->fps_num}; - enc->context->pix_fmt = obs_to_ffmpeg_video_format(info->format); + enc->context->pix_fmt = pix_fmt; enc->context->color_range = info->range == VIDEO_RANGE_FULL ? AVCOL_RANGE_JPEG : AVCOL_RANGE_MPEG; + enum AVColorSpace colorspace = AVCOL_SPC_UNSPECIFIED; switch (info->colorspace) { case VIDEO_CS_601: enc->context->color_primaries = AVCOL_PRI_SMPTE170M; enc->context->color_trc = AVCOL_TRC_SMPTE170M; - enc->context->colorspace = AVCOL_SPC_SMPTE170M; + colorspace = AVCOL_SPC_SMPTE170M; break; case VIDEO_CS_DEFAULT: case VIDEO_CS_709: enc->context->color_primaries = AVCOL_PRI_BT709; enc->context->color_trc = AVCOL_TRC_BT709; - enc->context->colorspace = AVCOL_SPC_BT709; + colorspace = AVCOL_SPC_BT709; break; case VIDEO_CS_SRGB: enc->context->color_primaries = AVCOL_PRI_BT709; enc->context->color_trc = AVCOL_TRC_IEC61966_2_1; - enc->context->colorspace = AVCOL_SPC_BT709; + colorspace = AVCOL_SPC_BT709; break; case VIDEO_CS_2100_PQ: enc->context->color_primaries = AVCOL_PRI_BT2020; enc->context->color_trc = AVCOL_TRC_SMPTE2084; - enc->context->colorspace = AVCOL_SPC_BT2020_NCL; - enc->context->chroma_sample_location = AVCHROMA_LOC_TOPLEFT; + colorspace = AVCOL_SPC_BT2020_NCL; break; case VIDEO_CS_2100_HLG: enc->context->color_primaries = AVCOL_PRI_BT2020; enc->context->color_trc = AVCOL_TRC_ARIB_STD_B67; - enc->context->colorspace = AVCOL_SPC_BT2020_NCL; - enc->context->chroma_sample_location = AVCHROMA_LOC_TOPLEFT; + colorspace = AVCOL_SPC_BT2020_NCL; } + enc->context->colorspace = colorspace; + enc->context->chroma_sample_location = + determine_chroma_location(pix_fmt, colorspace); + if (keyint_sec) enc->context->gop_size = keyint_sec * voi->fps_num / voi->fps_den;
View file
obs-studio-28.1.2.tar.xz/plugins/obs-ffmpeg/obs-ffmpeg.c -> obs-studio-29.0.0.tar.xz/plugins/obs-ffmpeg/obs-ffmpeg.c
Changed
@@ -14,6 +14,13 @@ #include "jim-nvenc.h" #endif +#if !defined(_WIN32) && !defined(__APPLE__) && \ + LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(55, 27, 100) +#include "vaapi-utils.h" + +#define LIBAVUTIL_VAAPI_AVAILABLE +#endif + OBS_DECLARE_MODULE() OBS_MODULE_USE_DEFAULT_LOCALE("obs-ffmpeg", "en-US") MODULE_EXPORT const char *obs_module_description(void) @@ -36,10 +43,6 @@ extern struct obs_encoder_info svt_av1_encoder_info; extern struct obs_encoder_info aom_av1_encoder_info; -#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(55, 27, 100) -#define LIBAVUTIL_VAAPI_AVAILABLE -#endif - #ifdef LIBAVUTIL_VAAPI_AVAILABLE extern struct obs_encoder_info vaapi_encoder_info; #endif @@ -320,10 +323,16 @@ #endif #ifdef LIBAVUTIL_VAAPI_AVAILABLE -static bool vaapi_supported(void) +static bool h264_vaapi_supported(void) { const AVCodec *vaenc = avcodec_find_encoder_by_name("h264_vaapi"); - return !!vaenc; + + if (!vaenc) + return false; + + /* NOTE: If default device is NULL, it means there is no device + * that support H264. */ + return vaapi_get_h264_default_device() != NULL; } #endif @@ -403,10 +412,18 @@ amf_load(); #endif -#if !defined(_WIN32) && defined(LIBAVUTIL_VAAPI_AVAILABLE) - if (vaapi_supported()) { - blog(LOG_INFO, "FFMPEG VAAPI supported"); +#ifdef LIBAVUTIL_VAAPI_AVAILABLE + const char *libva_env = getenv("LIBVA_DRIVER_NAME"); + if (!!libva_env) + blog(LOG_WARNING, + "LIBVA_DRIVER_NAME variable is set," + " this could prevent FFmpeg VAAPI from working correctly"); + + if (h264_vaapi_supported()) { + blog(LOG_INFO, "FFmpeg VAAPI H264 encoding supported"); obs_register_encoder(&vaapi_encoder_info); + } else { + blog(LOG_INFO, "FFmpeg VAAPI H264 encoding not supported"); } #endif #endif
View file
obs-studio-28.1.2.tar.xz/plugins/obs-ffmpeg/obs-nvenc-test/jim-nvenc-test.c -> obs-studio-29.0.0.tar.xz/plugins/obs-ffmpeg/obs-nvenc-test/jim-nvenc-test.c
Changed
@@ -1,4 +1,5 @@ #include <stdbool.h> +#include <stdlib.h> #include <stdio.h> #include "../external/nvEncodeAPI.h" @@ -21,6 +22,8 @@ }; #define MAX_CAPS 10 +static uint32_t luid_count = 0; +static uint64_t luid_orderMAX_CAPS = {0}; static struct nvenc_info adapter_infoMAX_CAPS = {0}; bool load_nvenc_lib(void) @@ -37,11 +40,21 @@ return func_ptr; } +static inline uint32_t get_adapter_idx(uint32_t adapter_idx, LUID luid) +{ + for (uint32_t i = 0; i < luid_count; i++) { + if (luid_orderi == *(uint64_t *)&luid) { + return i; + } + } + + return adapter_idx; +} + static bool get_adapter_caps(IDXGIFactory *factory, uint32_t adapter_idx) { - struct nvenc_info *caps = &adapter_infoadapter_idx; + struct nvenc_info *caps; IDXGIAdapter *adapter = NULL; - IDXGIOutput *output = NULL; ID3D11Device *device = NULL; ID3D11DeviceContext *context = NULL; GUID *guids = NULL; @@ -58,15 +71,12 @@ DXGI_ADAPTER_DESC desc; adapter->lpVtbl->GetDesc(adapter, &desc); + caps = &adapter_infoget_adapter_idx(adapter_idx, desc.AdapterLuid); if (desc.VendorId != NVIDIA_VENDOR_ID) return true; caps->is_nvidia = true; - hr = adapter->lpVtbl->EnumOutputs(adapter, 0, &output); - if (FAILED(hr)) - goto finish; - hr = D3D11CreateDevice(adapter, D3D_DRIVER_TYPE_UNKNOWN, NULL, 0, NULL, 0, D3D11_SDK_VERSION, &device, NULL, &context); if (FAILED(hr)) @@ -111,8 +121,6 @@ context->lpVtbl->Release(context); if (device) device->lpVtbl->Release(device); - if (output) - output->lpVtbl->Release(output); if (adapter) adapter->lpVtbl->Release(adapter); return true; @@ -172,7 +180,7 @@ return 0; } -int main(void) +int main(int argc, char *argv) { IDXGIFactory *factory = NULL; HRESULT hr; @@ -193,6 +201,17 @@ if (!init_nvenc_internal()) return 0; + /* --------------------------------------------------------- */ + /* parse expected LUID order */ + + luid_count = argc - 1; + for (int i = 1; i < argc; i++) { + luid_orderi - 1 = strtoull(argvi, NULL, 16); + } + + /* --------------------------------------------------------- */ + /* obtain adapter compatibility information */ + hr = CreateDXGIFactory1(&IID_IDXGIFactory1, (void **)&factory); if (FAILED(hr)) return 0;
View file
obs-studio-28.1.2.tar.xz/plugins/obs-ffmpeg/texture-amf-opts.hpp -> obs-studio-29.0.0.tar.xz/plugins/obs-ffmpeg/texture-amf-opts.hpp
Changed
@@ -17,25 +17,40 @@ { bool avc = enc->codec == amf_codec_type::AVC; bool hevc = enc->codec == amf_codec_type::HEVC; + bool av1 = enc->codec == amf_codec_type::AV1; if (strcmp(opt->name, "g") == 0 || strcmp(opt->name, "keyint") == 0) { int val = atoi(opt->value); - if (enc->codec == amf_codec_type::AVC) + if (avc) set_avc_opt(IDR_PERIOD, val); - else + else if (hevc) set_hevc_opt(NUM_GOPS_PER_IDR, val); + else if (av1) + set_av1_opt(GOP_SIZE, val); } else if (strcmp(opt->name, "usage") == 0) { if (strcmp(opt->value, "transcoding") == 0) { - set_enum_opt(USAGE, TRANSCONDING); + set_enum_opt(USAGE, TRANSCODING); } else if (strcmp(opt->value, "ultralowlatency") == 0) { - set_enum_opt(USAGE, ULTRA_LOW_LATENCY); + if (avc) + set_avc_enum(USAGE, ULTRA_LOW_LATENCY); + else if (hevc) + set_hevc_enum(USAGE, ULTRA_LOW_LATENCY); + else + warn("Invalid value for %s: %s", opt->name, + opt->value); } else if (strcmp(opt->value, "lowlatency") == 0) { set_enum_opt(USAGE, LOW_LATENCY); } else if (strcmp(opt->value, "webcam") == 0) { - set_enum_opt(USAGE, WEBCAM); + if (avc) + set_avc_enum(USAGE, WEBCAM); + else if (hevc) + set_hevc_enum(USAGE, WEBCAM); + else + warn("Invalid value for %s: %s", opt->name, + opt->value); } else { warn("Invalid value for %s: %s", opt->name, opt->value); } @@ -69,7 +84,12 @@ val.erase(pos, 1); int level = std::stoi(val); - set_opt(PROFILE_LEVEL, level); + if (avc) + set_avc_opt(PROFILE_LEVEL, level); + else if (hevc) + set_hevc_opt(PROFILE_LEVEL, level); + else + warn("Invalid value for %s: %s", opt->name, opt->value); } else if (strcmp(opt->name, "quality") == 0) { @@ -106,42 +126,82 @@ } else if (strcmp(opt->name, "filler_data") == 0) { bool val = str_to_bool(opt->value); - set_opt(FILLER_DATA_ENABLE, val); + if (avc) + set_avc_opt(FILLER_DATA_ENABLE, val); + else if (hevc) + set_hevc_opt(FILLER_DATA_ENABLE, val); + else + warn("Invalid value for %s: %s", opt->name, opt->value); } else if (strcmp(opt->name, "vbaq") == 0) { bool val = str_to_bool(opt->value); - set_opt(ENABLE_VBAQ, val); + if (avc) + set_avc_opt(ENABLE_VBAQ, val); + else if (hevc) + set_hevc_opt(ENABLE_VBAQ, val); + else + warn("Invalid value for %s: %s", opt->name, opt->value); } else if (strcmp(opt->name, "qp_i") == 0) { int val = atoi(opt->value); - set_opt(QP_I, val); + if (avc) + set_avc_opt(QP_I, val); + else if (hevc) + set_hevc_opt(QP_I, val); + else + warn("Invalid value for %s: %s", opt->name, opt->value); } else if (strcmp(opt->name, "qp_p") == 0) { int val = atoi(opt->value); - set_opt(QP_P, val); + if (avc) + set_avc_opt(QP_P, val); + else if (hevc) + set_hevc_opt(QP_P, val); + else + warn("Invalid value for %s: %s", opt->name, opt->value); } else if (strcmp(opt->name, "me_half_pel") == 0) { bool val = str_to_bool(opt->value); - set_opt(MOTION_HALF_PIXEL, val); + if (avc) + set_avc_opt(MOTION_HALF_PIXEL, val); + else if (hevc) + set_hevc_opt(MOTION_HALF_PIXEL, val); + else + warn("Invalid value for %s: %s", opt->name, opt->value); } else if (strcmp(opt->name, "me_quarter_pel") == 0) { bool val = str_to_bool(opt->value); - set_opt(MOTION_QUARTERPIXEL, val); + if (avc) + set_avc_opt(MOTION_QUARTERPIXEL, val); + else if (hevc) + set_hevc_opt(MOTION_QUARTERPIXEL, val); + else + warn("Invalid value for %s: %s", opt->name, opt->value); } else if (strcmp(opt->name, "aud") == 0) { bool val = str_to_bool(opt->value); - set_opt(INSERT_AUD, val); + if (avc) + set_avc_opt(INSERT_AUD, val); + else if (hevc) + set_hevc_opt(INSERT_AUD, val); + else + warn("Invalid value for %s: %s", opt->name, opt->value); } else if (strcmp(opt->name, "max_au_size") == 0) { int val = atoi(opt->value); - set_opt(MAX_AU_SIZE, val); + if (avc) + set_avc_opt(MAX_AU_SIZE, val); + else if (hevc) + set_hevc_opt(MAX_AU_SIZE, val); + else + warn("Invalid value for %s: %s", opt->name, opt->value); } else if (avc && strcmp(opt->name, "preanalysis") == 0) {
View file
obs-studio-28.1.2.tar.xz/plugins/obs-ffmpeg/texture-amf.cpp -> obs-studio-29.0.0.tar.xz/plugins/obs-ffmpeg/texture-amf.cpp
Changed
@@ -8,7 +8,7 @@ #include <unordered_map> #include <cstdlib> #include <memory> -#include <string> +#include <sstream> #include <vector> #include <mutex> #include <deque> @@ -16,6 +16,7 @@ #include "external/AMF/include/components/VideoEncoderHEVC.h" #include "external/AMF/include/components/VideoEncoderVCE.h" +#include "external/AMF/include/components/VideoEncoderAV1.h" #include "external/AMF/include/core/Factory.h" #include "external/AMF/include/core/Trace.h" @@ -23,6 +24,7 @@ #include <d3d11.h> #include <d3d11_1.h> +#include <util/windows/device-enum.h> #include <util/windows/HRError.hpp> #include <util/windows/ComPtr.hpp> #include <util/platform.h> @@ -63,6 +65,7 @@ bool is_amd = false; bool supports_avc = false; bool supports_hevc = false; + bool supports_av1 = false; }; /* ------------------------------------------------------------------------- */ @@ -80,6 +83,7 @@ enum class amf_codec_type { AVC, HEVC, + AV1, }; struct amf_base { @@ -213,25 +217,34 @@ set_amf_property(enc, AMF_VIDEO_ENCODER_##name, value) #define set_hevc_property(enc, name, value) \ set_amf_property(enc, AMF_VIDEO_ENCODER_HEVC_##name, value) +#define set_av1_property(enc, name, value) \ + set_amf_property(enc, AMF_VIDEO_ENCODER_AV1_##name, value) #define get_avc_property(enc, name, value) \ get_amf_property(enc, AMF_VIDEO_ENCODER_##name, value) #define get_hevc_property(enc, name, value) \ get_amf_property(enc, AMF_VIDEO_ENCODER_HEVC_##name, value) +#define get_av1_property(enc, name, value) \ + get_amf_property(enc, AMF_VIDEO_ENCODER_AV1_##name, value) #define get_opt_name(name) \ ((enc->codec == amf_codec_type::AVC) ? AMF_VIDEO_ENCODER_##name \ - : AMF_VIDEO_ENCODER_HEVC_##name) + : (enc->codec == amf_codec_type::HEVC) \ + ? AMF_VIDEO_ENCODER_HEVC_##name \ + : AMF_VIDEO_ENCODER_AV1_##name) #define set_opt(name, value) set_amf_property(enc, get_opt_name(name), value) #define get_opt(name, value) get_amf_property(enc, get_opt_name(name), value) #define set_avc_opt(name, value) set_avc_property(enc, name, value) #define set_hevc_opt(name, value) set_hevc_property(enc, name, value) +#define set_av1_opt(name, value) set_av1_property(enc, name, value) #define set_enum_opt(name, value) \ set_amf_property(enc, get_opt_name(name), get_opt_name(name##_##value)) #define set_avc_enum(name, value) \ set_avc_property(enc, name, AMF_VIDEO_ENCODER_##name##_##value) #define set_hevc_enum(name, value) \ set_hevc_property(enc, name, AMF_VIDEO_ENCODER_HEVC_##name##_##value) +#define set_av1_enum(name, value) \ + set_av1_property(enc, name, AMF_VIDEO_ENCODER_AV1_##name##_##value) /* ------------------------------------------------------------------------- */ /* Implementation */ @@ -397,32 +410,78 @@ mb_frame * (amf_int64)enc->fps_num / (amf_int64)enc->fps_den; } +static inline int get_avc_preset(amf_base *enc, const char *preset); +#if ENABLE_HEVC +static inline int get_hevc_preset(amf_base *enc, const char *preset); +#endif +static inline int get_av1_preset(amf_base *enc, const char *preset); + +static inline int get_preset(amf_base *enc, const char *preset) +{ + if (enc->codec == amf_codec_type::AVC) + return get_avc_preset(enc, preset); + +#if ENABLE_HEVC + else if (enc->codec == amf_codec_type::HEVC) + return get_hevc_preset(enc, preset); + +#endif + else if (enc->codec == amf_codec_type::AV1) + return get_av1_preset(enc, preset); + + return 0; +} + +static inline void refresh_throughput_caps(amf_base *enc, const char *&preset) +{ + AMF_RESULT res = AMF_OK; + AMFCapsPtr caps; + + set_opt(QUALITY_PRESET, get_preset(enc, preset)); + res = enc->amf_encoder->GetCaps(&caps); + if (res == AMF_OK) { + caps->GetProperty(get_opt_name(CAP_MAX_THROUGHPUT), + &enc->max_throughput); + } +} + static inline void check_preset_compatibility(amf_base *enc, const char *&preset) { - /* 1.8 * current base throughput == quality, - * 1.1 * current base throughput == balanced */ - static constexpr amf_int64 throughput_quality_mul = 18; - static constexpr amf_int64 throughput_balanced_mul = 11; + /* The throughput depends on the current preset and the other static + * encoder properties. If the throughput is lower than the max + * throughput, switch to a lower preset. */ + + if (astrcmpi(preset, "highQuality") == 0) { + if (!enc->max_throughput) { + preset = "quality"; + set_opt(QUALITY_PRESET, get_preset(enc, preset)); + } else { + if (enc->max_throughput < enc->throughput) { + preset = "quality"; + refresh_throughput_caps(enc, preset); + } + } + } - /* if the throughput * 1.8 is lower than the max throughput, switch to - * a lower preset */ if (astrcmpi(preset, "quality") == 0) { if (!enc->max_throughput) { preset = "balanced"; + set_opt(QUALITY_PRESET, get_preset(enc, preset)); } else { - amf_int64 req_throughput = - enc->throughput * throughput_quality_mul / 10; - if (enc->max_throughput < req_throughput) + if (enc->max_throughput < enc->throughput) { preset = "balanced"; + refresh_throughput_caps(enc, preset); + } } } if (astrcmpi(preset, "balanced") == 0) { - amf_int64 req_throughput = - enc->throughput * throughput_balanced_mul / 10; - if (enc->max_throughput && enc->max_throughput < req_throughput) + if (enc->max_throughput && + enc->max_throughput < enc->throughput) { preset = "speed"; + refresh_throughput_caps(enc, preset); + } } } @@ -447,29 +506,62 @@ enc->packet_data = AMFBufferPtr(data); data->GetProperty(L"PTS", &packet->pts); - bool hevc = enc->codec == amf_codec_type::HEVC; - const wchar_t *get_output_type = - hevc ? AMF_VIDEO_ENCODER_HEVC_OUTPUT_DATA_TYPE - : AMF_VIDEO_ENCODER_OUTPUT_DATA_TYPE; - - uint64_t type; - data->GetProperty(get_output_type, &type); - - switch (type) { - case AMF_VIDEO_ENCODER_OUTPUT_DATA_TYPE_IDR: - packet->priority = OBS_NAL_PRIORITY_HIGHEST; - break; - case AMF_VIDEO_ENCODER_OUTPUT_DATA_TYPE_I: - packet->priority = OBS_NAL_PRIORITY_HIGH; + const wchar_t *get_output_type; + switch (enc->codec) { + case amf_codec_type::AVC: + get_output_type = AMF_VIDEO_ENCODER_OUTPUT_DATA_TYPE; break; - case AMF_VIDEO_ENCODER_OUTPUT_DATA_TYPE_P: - packet->priority = OBS_NAL_PRIORITY_LOW; + case amf_codec_type::HEVC: + get_output_type = AMF_VIDEO_ENCODER_HEVC_OUTPUT_DATA_TYPE; break; - case AMF_VIDEO_ENCODER_OUTPUT_DATA_TYPE_B: - packet->priority = OBS_NAL_PRIORITY_DISPOSABLE; + case amf_codec_type::AV1: + get_output_type = AMF_VIDEO_ENCODER_AV1_OUTPUT_FRAME_TYPE; break; } + uint64_t type = 0; + AMF_RESULT res = data->GetProperty(get_output_type, &type); + if (res != AMF_OK) + throw amf_error("Failed to GetProperty(): encoder output " + "data type", + res); + + if (enc->codec == amf_codec_type::AVC || + enc->codec == amf_codec_type::HEVC) { + switch (type) { + case AMF_VIDEO_ENCODER_OUTPUT_DATA_TYPE_IDR: + packet->priority = OBS_NAL_PRIORITY_HIGHEST; + break; + case AMF_VIDEO_ENCODER_OUTPUT_DATA_TYPE_I: + packet->priority = OBS_NAL_PRIORITY_HIGH; + break; + case AMF_VIDEO_ENCODER_OUTPUT_DATA_TYPE_P: + packet->priority = OBS_NAL_PRIORITY_LOW; + break; + case AMF_VIDEO_ENCODER_OUTPUT_DATA_TYPE_B: + packet->priority = OBS_NAL_PRIORITY_DISPOSABLE; + break; + } + } else if (enc->codec == amf_codec_type::AV1) { + switch (type) { + case AMF_VIDEO_ENCODER_AV1_OUTPUT_FRAME_TYPE_KEY: + packet->priority = OBS_NAL_PRIORITY_HIGHEST; + break; + case AMF_VIDEO_ENCODER_AV1_OUTPUT_FRAME_TYPE_INTRA_ONLY: + packet->priority = OBS_NAL_PRIORITY_HIGH; + break; + case AMF_VIDEO_ENCODER_AV1_OUTPUT_FRAME_TYPE_INTER: + packet->priority = OBS_NAL_PRIORITY_LOW; + break; + case AMF_VIDEO_ENCODER_AV1_OUTPUT_FRAME_TYPE_SWITCH: + packet->priority = OBS_NAL_PRIORITY_DISPOSABLE; + break; + case AMF_VIDEO_ENCODER_AV1_OUTPUT_FRAME_TYPE_SHOW_EXISTING: + packet->priority = OBS_NAL_PRIORITY_DISPOSABLE; + break; + } + } + packet->data = (uint8_t *)enc->packet_data->GetNative(); packet->size = enc->packet_data->GetSize(); packet->type = OBS_ENCODER_VIDEO; @@ -769,6 +861,23 @@ } } +static void av1_video_info_fallback(void *, struct video_scale_info *info) +{ + switch (info->format) { + case VIDEO_FORMAT_RGBA: + case VIDEO_FORMAT_BGRA: + case VIDEO_FORMAT_BGRX: + info->format = VIDEO_FORMAT_RGBA; + break; + case VIDEO_FORMAT_I010: + case VIDEO_FORMAT_P010: + info->format = VIDEO_FORMAT_P010; + break; + default: + info->format = VIDEO_FORMAT_NV12; + } +} + static bool amf_create_encoder(amf_base *enc) try { AMF_RESULT res; @@ -787,8 +896,10 @@ if (enc->fallback) { if (enc->codec == amf_codec_type::AVC) h264_video_info_fallback(NULL, &info); - else + else if (enc->codec == amf_codec_type::HEVC) h265_video_info_fallback(NULL, &info); + else + av1_video_info_fallback(NULL, &info); } enc->cx = obs_encoder_get_width(enc->encoder); @@ -868,10 +979,21 @@ enc->init(); - res = amf_factory->CreateComponent(enc->amf_context, - enc->codec == amf_codec_type::HEVC - ? AMFVideoEncoder_HEVC - : AMFVideoEncoderVCE_AVC, + const wchar_t *codec = nullptr; + switch (enc->codec) { + case (amf_codec_type::AVC): + codec = AMFVideoEncoderVCE_AVC; + break; + case (amf_codec_type::HEVC): + codec = AMFVideoEncoder_HEVC; + break; + case (amf_codec_type::AV1): + codec = AMFVideoEncoder_AV1; + break; + default: + codec = AMFVideoEncoder_HEVC; + } + res = amf_factory->CreateComponent(enc->amf_context, codec, &enc->amf_encoder); if (res != AMF_OK) throw amf_error("CreateComponent failed", res); @@ -891,14 +1013,19 @@ delete enc; } -static void check_texture_encode_capability(obs_encoder_t *encoder, bool hevc) +static void check_texture_encode_capability(obs_encoder_t *encoder, + amf_codec_type codec) { obs_video_info ovi; obs_get_video_info(&ovi); + bool avc = amf_codec_type::AVC == codec; + bool hevc = amf_codec_type::HEVC == codec; + bool av1 = amf_codec_type::AV1 == codec; if (obs_encoder_scaling_enabled(encoder)) throw "Encoder scaling is active"; - if (hevc) { + + if (hevc || av1) { if (!obs_nv12_tex_active() && !obs_p010_tex_active()) throw "NV12/P010 textures aren't active"; } else if (!obs_nv12_tex_active()) { @@ -919,8 +1046,9 @@ } } - if ((hevc && !capsovi.adapter.supports_hevc) || - (!hevc && !capsovi.adapter.supports_avc)) + if ((avc && !capsovi.adapter.supports_avc) || + (hevc && !capsovi.adapter.supports_hevc) || + (av1 && !capsovi.adapter.supports_av1)) throw "Wrong adapter"; } @@ -948,7 +1076,7 @@ return true; } -static obs_properties_t *amf_properties_internal(bool hevc) +static obs_properties_t *amf_properties_internal(amf_codec_type codec) { obs_properties_t *props = obs_properties_create(); obs_property_t *p; @@ -960,6 +1088,10 @@ obs_property_list_add_string(p, "CBR", "CBR"); obs_property_list_add_string(p, "CQP", "CQP"); obs_property_list_add_string(p, "VBR", "VBR"); + obs_property_list_add_string(p, "VBR_LAT", "VBR_LAT"); + obs_property_list_add_string(p, "QVBR", "QVBR"); + obs_property_list_add_string(p, "HQVBR", "HQVBR"); + obs_property_list_add_string(p, "HQCBR", "HQCBR"); obs_property_set_modified_callback(p, rate_control_modified); @@ -968,7 +1100,7 @@ obs_property_int_set_suffix(p, " Kbps"); obs_properties_add_int(props, "cqp", obs_module_text("NVENC.CQLevel"), - 1, 30, 1); + 0, codec == amf_codec_type::AV1 ? 63 : 51, 1); p = obs_properties_add_int(props, "keyint_sec", obs_module_text("KeyframeIntervalSec"), 0, @@ -981,23 +1113,30 @@ #define add_preset(val) \ obs_property_list_add_string(p, obs_module_text("AMF.Preset." val), val) + if (amf_codec_type::AV1 == codec) { + add_preset("highQuality"); + } add_preset("quality"); add_preset("balanced"); add_preset("speed"); #undef add_preset - if (!hevc) { + if (amf_codec_type::AVC == codec || amf_codec_type::AV1 == codec) { p = obs_properties_add_list(props, "profile", obs_module_text("Profile"), OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_STRING); #define add_profile(val) obs_property_list_add_string(p, val, val) - add_profile("high"); + if (amf_codec_type::AVC == codec) + add_profile("high"); add_profile("main"); - add_profile("baseline"); + if (amf_codec_type::AVC == codec) + add_profile("baseline"); #undef add_profile + } + if (amf_codec_type::AVC == codec) { obs_properties_add_int(props, "bf", obs_module_text("BFrames"), 0, 5, 1); } @@ -1014,13 +1153,19 @@ static obs_properties_t *amf_avc_properties(void *unused) { UNUSED_PARAMETER(unused); - return amf_properties_internal(false); + return amf_properties_internal(amf_codec_type::AVC); } static obs_properties_t *amf_hevc_properties(void *unused) { UNUSED_PARAMETER(unused); - return amf_properties_internal(true); + return amf_properties_internal(amf_codec_type::HEVC); +} + +static obs_properties_t *amf_av1_properties(void *unused) +{ + UNUSED_PARAMETER(unused); + return amf_properties_internal(amf_codec_type::AV1); } /* ========================================================================= */ @@ -1028,15 +1173,11 @@ static const char *amf_avc_get_name(void *) { - return "AMD HW H.264"; + return "AMD HW H.264 (AVC)"; } -static inline int get_avc_preset(amf_base *enc, obs_data_t *settings) +static inline int get_avc_preset(amf_base *enc, const char *preset) { - const char *preset = obs_data_get_string(settings, "preset"); - - check_preset_compatibility(enc, preset); - if (astrcmpi(preset, "quality") == 0) return AMF_VIDEO_ENCODER_QUALITY_PRESET_QUALITY; else if (astrcmpi(preset, "speed") == 0) @@ -1049,8 +1190,18 @@ { if (astrcmpi(rc_str, "cqp") == 0) return AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_CONSTANT_QP; + else if (astrcmpi(rc_str, "cbr") == 0) + return AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_CBR; else if (astrcmpi(rc_str, "vbr") == 0) return AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_PEAK_CONSTRAINED_VBR; + else if (astrcmpi(rc_str, "vbr_lat") == 0) + return AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_LATENCY_CONSTRAINED_VBR; + else if (astrcmpi(rc_str, "qvbr") == 0) + return AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_QUALITY_VBR; + else if (astrcmpi(rc_str, "hqvbr") == 0) + return AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_HIGH_QUALITY_VBR; + else if (astrcmpi(rc_str, "hqcbr") == 0) + return AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_HIGH_QUALITY_CBR; return AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_CBR; } @@ -1130,8 +1281,6 @@ const char *rc_str = obs_data_get_string(settings, "rate_control"); int64_t bf = obs_data_get_int(settings, "bf"); - check_preset_compatibility(enc, preset); - if (enc->bframes_supported) { set_avc_property(enc, MAX_CONSECUTIVE_BPICTURES, 3); set_avc_property(enc, B_PIC_PATTERN, bf); @@ -1146,7 +1295,8 @@ int rc = get_avc_rate_control(rc_str); set_avc_property(enc, RATE_CONTROL_METHOD, rc); - set_avc_property(enc, ENABLE_VBAQ, true); + if (rc != AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_CONSTANT_QP) + set_avc_property(enc, ENABLE_VBAQ, true); amf_avc_update_data(enc, rc, bitrate * 1000, qp); @@ -1165,6 +1315,8 @@ set_avc_property(enc, DE_BLOCKING_FILTER, true); + check_preset_compatibility(enc, preset); + const char *ffmpeg_opts = obs_data_get_string(settings, "ffmpeg_opts"); if (ffmpeg_opts && *ffmpeg_opts) { struct obs_options opts = obs_parse_options(ffmpeg_opts); @@ -1213,9 +1365,11 @@ &enc->max_throughput); } + const char *preset = obs_data_get_string(settings, "preset"); + set_avc_property(enc, FRAMESIZE, AMFConstructSize(enc->cx, enc->cy)); set_avc_property(enc, USAGE, AMF_VIDEO_ENCODER_USAGE_TRANSCODING); - set_avc_property(enc, QUALITY_PRESET, get_avc_preset(enc, settings)); + set_avc_property(enc, QUALITY_PRESET, get_avc_preset(enc, preset)); set_avc_property(enc, PROFILE, get_avc_profile(settings)); set_avc_property(enc, LOWLATENCY_MODE, false); set_avc_property(enc, CABAC_ENABLE, AMF_VIDEO_ENCODER_UNDEFINED); @@ -1253,7 +1407,7 @@ static void *amf_avc_create_texencode(obs_data_t *settings, obs_encoder_t *encoder) try { - check_texture_encode_capability(encoder, false); + check_texture_encode_capability(encoder, amf_codec_type::AVC); std::unique_ptr<amf_texencode> enc = std::make_unique<amf_texencode>(); enc->encoder = encoder; @@ -1357,12 +1511,8 @@ return "AMD HW H.265 (HEVC)"; } -static inline int get_hevc_preset(amf_base *enc, obs_data_t *settings) +static inline int get_hevc_preset(amf_base *enc, const char *preset) { - const char *preset = obs_data_get_string(settings, "preset"); - - check_preset_compatibility(enc, preset); - if (astrcmpi(preset, "balanced") == 0) return AMF_VIDEO_ENCODER_HEVC_QUALITY_PRESET_BALANCED; else if (astrcmpi(preset, "speed") == 0) @@ -1375,8 +1525,18 @@ { if (astrcmpi(rc_str, "cqp") == 0) return AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD_CONSTANT_QP; + else if (astrcmpi(rc_str, "vbr_lat") == 0) + return AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD_LATENCY_CONSTRAINED_VBR; else if (astrcmpi(rc_str, "vbr") == 0) return AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD_PEAK_CONSTRAINED_VBR; + else if (astrcmpi(rc_str, "cbr") == 0) + return AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD_CBR; + else if (astrcmpi(rc_str, "qvbr") == 0) + return AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD_QUALITY_VBR; + else if (astrcmpi(rc_str, "hqvbr") == 0) + return AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD_HIGH_QUALITY_VBR; + else if (astrcmpi(rc_str, "hqcbr") == 0) + return AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD_HIGH_QUALITY_CBR; return AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD_CBR; } @@ -1440,7 +1600,8 @@ int rc = get_hevc_rate_control(rc_str); set_hevc_property(enc, RATE_CONTROL_METHOD, rc); - set_hevc_property(enc, ENABLE_VBAQ, true); + if (rc != AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD_CONSTANT_QP) + set_hevc_property(enc, ENABLE_VBAQ, true); amf_hevc_update_data(enc, rc, bitrate * 1000, qp); @@ -1453,6 +1614,8 @@ set_hevc_property(enc, GOP_SIZE, gop_size); + check_preset_compatibility(enc, preset); + const char *ffmpeg_opts = obs_data_get_string(settings, "ffmpeg_opts"); if (ffmpeg_opts && *ffmpeg_opts) { struct obs_options opts = obs_parse_options(ffmpeg_opts); @@ -1526,10 +1689,11 @@ const bool pq = is_pq(enc); const bool hlg = is_hlg(enc); const bool is_hdr = pq || hlg; + const char *preset = obs_data_get_string(settings, "preset"); set_hevc_property(enc, FRAMESIZE, AMFConstructSize(enc->cx, enc->cy)); set_hevc_property(enc, USAGE, AMF_VIDEO_ENCODER_USAGE_TRANSCODING); - set_hevc_property(enc, QUALITY_PRESET, get_hevc_preset(enc, settings)); + set_hevc_property(enc, QUALITY_PRESET, get_hevc_preset(enc, preset)); set_hevc_property(enc, COLOR_BIT_DEPTH, is10bit ? AMF_COLOR_BIT_DEPTH_10 : AMF_COLOR_BIT_DEPTH_8); @@ -1585,7 +1749,7 @@ static void *amf_hevc_create_texencode(obs_data_t *settings, obs_encoder_t *encoder) try { - check_texture_encode_capability(encoder, true); + check_texture_encode_capability(encoder, amf_codec_type::HEVC); std::unique_ptr<amf_texencode> enc = std::make_unique<amf_texencode>(); enc->encoder = encoder; @@ -1678,8 +1842,323 @@ #endif //ENABLE_HEVC /* ========================================================================= */ +/* AV1 Implementation */ + +static const char *amf_av1_get_name(void *) +{ + return "AMD HW AV1"; +} + +static inline int get_av1_preset(amf_base *enc, const char *preset) +{ + if (astrcmpi(preset, "highquality") == 0) + return AMF_VIDEO_ENCODER_AV1_QUALITY_PRESET_HIGH_QUALITY; + else if (astrcmpi(preset, "quality") == 0) + return AMF_VIDEO_ENCODER_AV1_QUALITY_PRESET_QUALITY; + else if (astrcmpi(preset, "balanced") == 0) + return AMF_VIDEO_ENCODER_AV1_QUALITY_PRESET_BALANCED; + else if (astrcmpi(preset, "speed") == 0) + return AMF_VIDEO_ENCODER_AV1_QUALITY_PRESET_SPEED; + + return AMF_VIDEO_ENCODER_AV1_QUALITY_PRESET_BALANCED; +} + +static inline int get_av1_rate_control(const char *rc_str) +{ + if (astrcmpi(rc_str, "cqp") == 0) + return AMF_VIDEO_ENCODER_AV1_RATE_CONTROL_METHOD_CONSTANT_QP; + else if (astrcmpi(rc_str, "vbr_lat") == 0) + return AMF_VIDEO_ENCODER_AV1_RATE_CONTROL_METHOD_LATENCY_CONSTRAINED_VBR; + else if (astrcmpi(rc_str, "vbr") == 0) + return AMF_VIDEO_ENCODER_AV1_RATE_CONTROL_METHOD_PEAK_CONSTRAINED_VBR; + else if (astrcmpi(rc_str, "cbr") == 0) + return AMF_VIDEO_ENCODER_AV1_RATE_CONTROL_METHOD_CBR; + else if (astrcmpi(rc_str, "qvbr") == 0) + return AMF_VIDEO_ENCODER_AV1_RATE_CONTROL_METHOD_QUALITY_VBR; + else if (astrcmpi(rc_str, "hqvbr") == 0) + return AMF_VIDEO_ENCODER_AV1_RATE_CONTROL_METHOD_HIGH_QUALITY_VBR; + else if (astrcmpi(rc_str, "hqcbr") == 0) + return AMF_VIDEO_ENCODER_AV1_RATE_CONTROL_METHOD_HIGH_QUALITY_CBR; + + return AMF_VIDEO_ENCODER_AV1_RATE_CONTROL_METHOD_CBR; +} + +static inline int get_av1_profile(obs_data_t *settings) +{ + const char *profile = obs_data_get_string(settings, "profile"); + + if (astrcmpi(profile, "main") == 0) + return AMF_VIDEO_ENCODER_AV1_PROFILE_MAIN; + + return AMF_VIDEO_ENCODER_AV1_PROFILE_MAIN; +} + +static void amf_av1_update_data(amf_base *enc, int rc, int64_t bitrate, + int64_t cq_value) +{ + if (rc != AMF_VIDEO_ENCODER_AV1_RATE_CONTROL_METHOD_CONSTANT_QP) { + set_av1_property(enc, TARGET_BITRATE, bitrate); + set_av1_property(enc, PEAK_BITRATE, bitrate); + set_av1_property(enc, VBV_BUFFER_SIZE, bitrate); + + if (rc == AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_CBR) { + set_av1_property(enc, FILLER_DATA, true); + } else if ( + rc == AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_PEAK_CONSTRAINED_VBR || + rc == AMF_VIDEO_ENCODER_AV1_RATE_CONTROL_METHOD_HIGH_QUALITY_VBR) { + set_av1_property(enc, PEAK_BITRATE, bitrate * 1.5); + } + } else { + int64_t qp = cq_value * 4; + set_av1_property(enc, Q_INDEX_INTRA, qp); + set_av1_property(enc, Q_INDEX_INTER, qp); + } +} + +static bool amf_av1_update(void *data, obs_data_t *settings) +try { + amf_base *enc = (amf_base *)data; + + if (enc->first_update) { + enc->first_update = false; + return true; + } + + int64_t bitrate = obs_data_get_int(settings, "bitrate"); + int64_t cq_level = obs_data_get_int(settings, "cqp"); + const char *rc_str = obs_data_get_string(settings, "rate_control"); + int rc = get_av1_rate_control(rc_str); + + amf_av1_update_data(enc, rc, bitrate * 1000, cq_level); + + AMF_RESULT res = enc->amf_encoder->ReInit(enc->cx, enc->cy); + if (res != AMF_OK) + throw amf_error("AMFComponent::Init failed", res); + + return true; + +} catch (const amf_error &err) { + amf_base *enc = (amf_base *)data; + error("%s: %s: %ls", __FUNCTION__, err.str, + amf_trace->GetResultText(err.res)); + return false; +} + +static bool amf_av1_init(void *data, obs_data_t *settings) +{ + amf_base *enc = (amf_base *)data; + + int64_t bitrate = obs_data_get_int(settings, "bitrate"); + int64_t qp = obs_data_get_int(settings, "cqp"); + const char *preset = obs_data_get_string(settings, "preset"); + const char *profile = obs_data_get_string(settings, "profile"); + const char *rc_str = obs_data_get_string(settings, "rate_control"); + + int rc = get_av1_rate_control(rc_str); + set_av1_property(enc, RATE_CONTROL_METHOD, rc); + + amf_av1_update_data(enc, rc, bitrate * 1000, qp); + + set_av1_property(enc, ENFORCE_HRD, true); + + int keyint_sec = (int)obs_data_get_int(settings, "keyint_sec"); + int gop_size = (keyint_sec) ? keyint_sec * enc->fps_num / enc->fps_den + : 250; + set_av1_property(enc, GOP_SIZE, gop_size); + + const char *ffmpeg_opts = obs_data_get_string(settings, "ffmpeg_opts"); + if (ffmpeg_opts && *ffmpeg_opts) { + struct obs_options opts = obs_parse_options(ffmpeg_opts); + for (size_t i = 0; i < opts.count; i++) { + amf_apply_opt(enc, &opts.optionsi); + } + obs_free_options(opts); + } + + check_preset_compatibility(enc, preset); + + if (!ffmpeg_opts || !*ffmpeg_opts) + ffmpeg_opts = "(none)"; + + info("settings:\n" + "\trate_control: %s\n" + "\tbitrate: %d\n" + "\tcqp: %d\n" + "\tkeyint: %d\n" + "\tpreset: %s\n" + "\tprofile: %s\n" + "\twidth: %d\n" + "\theight: %d\n" + "\tparams: %s", + rc_str, bitrate, qp, gop_size, preset, profile, enc->cx, enc->cy, + ffmpeg_opts); + + return true; +} + +static void amf_av1_create_internal(amf_base *enc, obs_data_t *settings) +{ + enc->codec = amf_codec_type::AV1; + + if (!amf_create_encoder(enc)) + throw "Failed to create encoder"; + + AMFCapsPtr caps; + AMF_RESULT res = enc->amf_encoder->GetCaps(&caps); + if (res == AMF_OK) { + caps->GetProperty(AMF_VIDEO_ENCODER_AV1_CAP_MAX_THROUGHPUT, + &enc->max_throughput); + } + + const bool is10bit = enc->amf_format == AMF_SURFACE_P010; + const char *preset = obs_data_get_string(settings, "preset"); + + set_av1_property(enc, FRAMESIZE, AMFConstructSize(enc->cx, enc->cy)); + set_av1_property(enc, USAGE, AMF_VIDEO_ENCODER_USAGE_TRANSCODING); + set_av1_property(enc, ALIGNMENT_MODE, + AMF_VIDEO_ENCODER_AV1_ALIGNMENT_MODE_NO_RESTRICTIONS); + set_av1_property(enc, QUALITY_PRESET, get_av1_preset(enc, preset)); + set_av1_property(enc, COLOR_BIT_DEPTH, + is10bit ? AMF_COLOR_BIT_DEPTH_10 + : AMF_COLOR_BIT_DEPTH_8); + set_av1_property(enc, PROFILE, get_av1_profile(settings)); + set_av1_property(enc, ENCODING_LATENCY_MODE, + AMF_VIDEO_ENCODER_AV1_ENCODING_LATENCY_MODE_NONE); + // set_av1_property(enc, RATE_CONTROL_PREENCODE, true); + set_av1_property(enc, OUTPUT_COLOR_PROFILE, enc->amf_color_profile); + set_av1_property(enc, OUTPUT_TRANSFER_CHARACTERISTIC, + enc->amf_characteristic); + set_av1_property(enc, OUTPUT_COLOR_PRIMARIES, enc->amf_primaries); + + amf_av1_init(enc, settings); + + res = enc->amf_encoder->Init(enc->amf_format, enc->cx, enc->cy); + if (res != AMF_OK) + throw amf_error("AMFComponent::Init failed", res); + + set_av1_property(enc, FRAMERATE, enc->amf_frame_rate); + + AMFVariant p; + res = enc->amf_encoder->GetProperty(AMF_VIDEO_ENCODER_AV1_EXTRA_DATA, + &p); + if (res == AMF_OK && p.type == AMF_VARIANT_INTERFACE) + enc->header = AMFBufferPtr(p.pInterface); +} + +static void *amf_av1_create_texencode(obs_data_t *settings, + obs_encoder_t *encoder) +try { + check_texture_encode_capability(encoder, amf_codec_type::AV1); + + std::unique_ptr<amf_texencode> enc = std::make_unique<amf_texencode>(); + enc->encoder = encoder; + enc->encoder_str = "texture-amf-av1"; + + if (!amf_init_d3d11(enc.get())) + throw "Failed to create D3D11"; + + amf_av1_create_internal(enc.get(), settings); + return enc.release(); + +} catch (const amf_error &err) { + blog(LOG_ERROR, "texture-amf-av1 %s: %s: %ls", __FUNCTION__, err.str, + amf_trace->GetResultText(err.res)); + return obs_encoder_create_rerouted(encoder, "av1_fallback_amf"); + +} catch (const char *err) { + blog(LOG_ERROR, "texture-amf-av1 %s: %s", __FUNCTION__, err); + return obs_encoder_create_rerouted(encoder, "av1_fallback_amf"); +} + +static void *amf_av1_create_fallback(obs_data_t *settings, + obs_encoder_t *encoder) +try { + std::unique_ptr<amf_fallback> enc = std::make_unique<amf_fallback>(); + enc->encoder = encoder; + enc->encoder_str = "fallback-amf-av1"; + + video_t *video = obs_encoder_video(encoder); + const struct video_output_info *voi = video_output_get_info(video); + switch (voi->format) { + case VIDEO_FORMAT_I010: + case VIDEO_FORMAT_P010: { + break; + } + default: + switch (voi->colorspace) { + case VIDEO_CS_2100_PQ: + case VIDEO_CS_2100_HLG: { + const char *const text = + obs_module_text("AMF.8bitUnsupportedHdr"); + obs_encoder_set_last_error(encoder, text); + throw text; + } + } + } + + amf_av1_create_internal(enc.get(), settings); + return enc.release(); + +} catch (const amf_error &err) { + blog(LOG_ERROR, "fallback-amf-av1 %s: %s: %ls", __FUNCTION__, err.str, + amf_trace->GetResultText(err.res)); + return nullptr; + +} catch (const char *err) { + blog(LOG_ERROR, "fallback-amf-av1 %s: %s", __FUNCTION__, err); + return nullptr; +} + +static void amf_av1_defaults(obs_data_t *settings) +{ + obs_data_set_default_int(settings, "bitrate", 2500); + obs_data_set_default_int(settings, "cqp", 20); + obs_data_set_default_string(settings, "rate_control", "CBR"); + obs_data_set_default_string(settings, "preset", "quality"); + obs_data_set_default_string(settings, "profile", "high"); +} + +static void register_av1() +{ + struct obs_encoder_info amf_encoder_info = {}; + amf_encoder_info.id = "av1_texture_amf"; + amf_encoder_info.type = OBS_ENCODER_VIDEO; + amf_encoder_info.codec = "av1"; + amf_encoder_info.get_name = amf_av1_get_name; + amf_encoder_info.create = amf_av1_create_texencode; + amf_encoder_info.destroy = amf_destroy; + amf_encoder_info.update = amf_av1_update; + amf_encoder_info.encode_texture = amf_encode_tex; + amf_encoder_info.get_defaults = amf_av1_defaults; + amf_encoder_info.get_properties = amf_av1_properties; + amf_encoder_info.get_extra_data = amf_extra_data; + amf_encoder_info.caps = OBS_ENCODER_CAP_PASS_TEXTURE | + OBS_ENCODER_CAP_DYN_BITRATE; + + obs_register_encoder(&amf_encoder_info); + + amf_encoder_info.id = "av1_fallback_amf"; + amf_encoder_info.caps = OBS_ENCODER_CAP_INTERNAL | + OBS_ENCODER_CAP_DYN_BITRATE; + amf_encoder_info.encode_texture = nullptr; + amf_encoder_info.create = amf_av1_create_fallback; + amf_encoder_info.encode = amf_encode_fallback; + amf_encoder_info.get_video_info = av1_video_info_fallback; + + obs_register_encoder(&amf_encoder_info); +} + +/* ========================================================================= */ /* Global Stuff */ +static bool enum_luids(void *param, uint32_t idx, uint64_t luid) +{ + std::stringstream &cmd = *(std::stringstream *)param; + cmd << " " << std::hex << luid; + UNUSED_PARAMETER(idx); + return true; +} + extern "C" void amf_load(void) try { AMF_RESULT res; @@ -1694,12 +2173,16 @@ FreeLibrary(amf_module_test); /* ----------------------------------- */ - /* Check for AVC/HEVC support */ + /* Check for supported codecs */ BPtr<char> test_exe = os_get_executable_path_ptr("obs-amf-test.exe"); + std::stringstream cmd; std::string caps_str; - os_process_pipe_t *pp = os_process_pipe_create(test_exe, "r"); + cmd << test_exe; + enum_graphics_device_luids(enum_luids, &cmd); + + os_process_pipe_t *pp = os_process_pipe_create(cmd.str().c_str(), "r"); if (!pp) throw "Failed to launch the AMF test process I guess"; @@ -1731,6 +2214,7 @@ uint32_t adapter_count = (uint32_t)config_num_sections(config); bool avc_supported = false; bool hevc_supported = false; + bool av1_supported = false; for (uint32_t i = 0; i < adapter_count; i++) { std::string section = std::to_string(i); @@ -1742,13 +2226,16 @@ "supports_avc"); info.supports_hevc = config_get_bool(config, section.c_str(), "supports_hevc"); + info.supports_av1 = config_get_bool(config, section.c_str(), + "supports_av1"); avc_supported |= info.supports_avc; hevc_supported |= info.supports_hevc; + av1_supported |= info.supports_av1; } - if (!avc_supported && !hevc_supported) - throw "Neither AVC nor HEVC are supported by any devices"; + if (!avc_supported && !hevc_supported && !av1_supported) + throw "Neither AVC, HEVC, nor AV1 are supported by any devices"; /* ----------------------------------- */ /* Init AMF */ @@ -1793,6 +2280,8 @@ if (hevc_supported) register_hevc(); #endif + if (av1_supported) + register_av1(); } catch (const std::string &str) { /* doing debug here because string exceptions indicate the user is
View file
obs-studio-29.0.0.tar.xz/plugins/obs-ffmpeg/vaapi-utils.c
Added
@@ -0,0 +1,262 @@ +// SPDX-FileCopyrightText: 2022 tytan652 <tytan652@tytanium.xyz> +// +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "vaapi-utils.h" + +#include <util/bmem.h> +#include <util/dstr.h> + +#include <va/va_drm.h> +#include <va/va_str.h> + +#include <stdio.h> +#include <unistd.h> +#include <fcntl.h> + +static bool version_logged = false; + +inline static VADisplay vaapi_open_display_drm(int *fd, const char *device_path) +{ + VADisplay va_dpy; + + if (!device_path) + return NULL; + + *fd = open(device_path, O_RDWR); + if (*fd < 0) { + blog(LOG_ERROR, "VAAPI: Failed to open device '%s'", + device_path); + return NULL; + } + + va_dpy = vaGetDisplayDRM(*fd); + + if (!va_dpy) { + blog(LOG_ERROR, "VAAPI: Failed to initialize DRM display"); + return NULL; + } + + return va_dpy; +} + +inline static void vaapi_close_display_drm(int *fd) +{ + if (*fd < 0) + return; + + close(*fd); + *fd = -1; +} + +static void vaapi_log_info_cb(void *user_context, const char *message) +{ + UNUSED_PARAMETER(user_context); + + // Libva message always ends with a newline + struct dstr m; + dstr_init_copy(&m, message); + dstr_depad(&m); + + blog(LOG_DEBUG, "Libva: %s", m.array); + + dstr_free(&m); +} + +static void vaapi_log_error_cb(void *user_context, const char *message) +{ + UNUSED_PARAMETER(user_context); + + // Libva message always ends with a newline + struct dstr m; + dstr_init_copy(&m, message); + dstr_depad(&m); + + blog(LOG_DEBUG, "Libva error: %s", m.array); + + dstr_free(&m); +} + +VADisplay vaapi_open_device(int *fd, const char *device_path, + const char *func_name) +{ + VADisplay va_dpy; + VAStatus va_status; + int major, minor; + const char *driver; + + va_dpy = vaapi_open_display_drm(fd, device_path); + if (!va_dpy) + return NULL; + + blog(LOG_DEBUG, "VAAPI: Initializing display in %s", func_name); + + vaSetInfoCallback(va_dpy, vaapi_log_info_cb, NULL); + vaSetErrorCallback(va_dpy, vaapi_log_error_cb, NULL); + + va_status = vaInitialize(va_dpy, &major, &minor); + + if (va_status != VA_STATUS_SUCCESS) { + blog(LOG_ERROR, "VAAPI: Failed to initialize display in %s", + func_name); + return NULL; + } + + blog(LOG_DEBUG, "VAAPI: Display initialized"); + + if (!version_logged) { + blog(LOG_INFO, "VAAPI: API version %d.%d", major, minor); + version_logged = true; + } + + driver = vaQueryVendorString(va_dpy); + + blog(LOG_DEBUG, "VAAPI: '%s' in use for device '%s'", driver, + device_path); + + return va_dpy; +} + +void vaapi_close_device(int *fd, VADisplay dpy) +{ + vaTerminate(dpy); + vaapi_close_display_drm(fd); +} + +static uint32_t vaapi_display_ep_combo_rate_controls(VAProfile profile, + VAEntrypoint entrypoint, + VADisplay dpy, + const char *device_path) +{ + bool ret = false; + VAStatus va_status; + VAConfigAttrib attrib1; + attrib->type = VAConfigAttribRateControl; + + va_status = vaGetConfigAttributes(dpy, profile, entrypoint, attrib, 1); + + switch (va_status) { + case VA_STATUS_SUCCESS: + return attrib->value; + case VA_STATUS_ERROR_UNSUPPORTED_PROFILE: + blog(LOG_DEBUG, "VAAPI: %s is not supported by the device '%s'", + vaProfileStr(profile), device_path); + return 0; + case VA_STATUS_ERROR_UNSUPPORTED_ENTRYPOINT: + blog(LOG_DEBUG, + "VAAPI: %s %s is not supported by the device '%s'", + vaProfileStr(profile), vaEntrypointStr(entrypoint), + device_path); + return 0; + default: + blog(LOG_ERROR, + "VAAPI: Fail to get RC attribute from the %s %s of the device '%s'", + vaProfileStr(profile), vaEntrypointStr(entrypoint), + device_path); + return 0; + } +} + +static bool vaapi_display_ep_combo_supported(VAProfile profile, + VAEntrypoint entrypoint, + VADisplay dpy, + const char *device_path) +{ + uint32_t ret = vaapi_display_ep_combo_rate_controls(profile, entrypoint, + dpy, device_path); + if (ret & VA_RC_CBR || ret & VA_RC_CQP || ret & VA_RC_VBR) + return true; + + return false; +} + +bool vaapi_device_rc_supported(VAProfile profile, VADisplay dpy, uint32_t rc, + const char *device_path) +{ + uint32_t ret = vaapi_display_ep_combo_rate_controls( + profile, VAEntrypointEncSlice, dpy, device_path); + if (ret & rc) + return true; + ret = vaapi_display_ep_combo_rate_controls( + profile, VAEntrypointEncSliceLP, dpy, device_path); + if (ret & rc) + return true; + + return false; +} + +#define CHECK_PROFILE(ret, profile, va_dpy, device_path) \ + if (vaapi_display_ep_combo_supported(profile, VAEntrypointEncSlice, \ + va_dpy, device_path)) { \ + blog(LOG_DEBUG, "'%s' support encoding with %s", device_path, \ + vaProfileStr(profile)); \ + ret |= true; \ + } + +#define CHECK_PROFILE_LP(ret, profile, va_dpy, device_path) \ + if (vaapi_display_ep_combo_supported(profile, VAEntrypointEncSliceLP, \ + va_dpy, device_path)) { \ + blog(LOG_DEBUG, "'%s' support low power encoding with %s", \ + device_path, vaProfileStr(profile)); \ + ret |= true; \ + } + +bool vaapi_display_h264_supported(VADisplay dpy, const char *device_path) +{ + bool ret = false; + + CHECK_PROFILE(ret, VAProfileH264ConstrainedBaseline, dpy, device_path); + CHECK_PROFILE(ret, VAProfileH264Main, dpy, device_path); + CHECK_PROFILE(ret, VAProfileH264High, dpy, device_path); + + if (!ret) { + CHECK_PROFILE_LP(ret, VAProfileH264ConstrainedBaseline, dpy, + device_path); + CHECK_PROFILE_LP(ret, VAProfileH264Main, dpy, device_path); + CHECK_PROFILE_LP(ret, VAProfileH264High, dpy, device_path); + } + + return ret; +} + +bool vaapi_device_h264_supported(const char *device_path) +{ + bool ret = false; + VADisplay va_dpy; + + int drm_fd = -1; + + va_dpy = vaapi_open_device(&drm_fd, device_path, + "vaapi_device_h264_supported"); + if (!va_dpy) + return false; + + ret = vaapi_display_h264_supported(va_dpy, device_path); + + vaapi_close_device(&drm_fd, va_dpy); + + return ret; +} + +const char *vaapi_get_h264_default_device() +{ + static const char *default_h264_device = NULL; + + if (!default_h264_device) { + bool ret = false; + char path32 = "/dev/dri/renderD1"; + for (int i = 28;; i++) { + sprintf(path, "/dev/dri/renderD1%d", i); + if (access(path, F_OK) != 0) + break; + + ret = vaapi_device_h264_supported(path); + if (ret) { + default_h264_device = strdup(path); + break; + } + } + } + + return default_h264_device; +}
View file
obs-studio-29.0.0.tar.xz/plugins/obs-ffmpeg/vaapi-utils.h
Added
@@ -0,0 +1,22 @@ +// SPDX-FileCopyrightText: 2022 tytan652 <tytan652@tytanium.xyz> +// +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include <util/base.h> + +#include <va/va.h> + +VADisplay vaapi_open_device(int *fd, const char *device_path, + const char *func_name); +void vaapi_close_device(int *fd, VADisplay dpy); + +bool vaapi_device_rc_supported(VAProfile profile, VADisplay dpy, uint32_t rc, + const char *device_path); + +bool vaapi_display_h264_supported(VADisplay dpy, const char *device_path); + +bool vaapi_device_h264_supported(const char *device_path); + +const char *vaapi_get_h264_default_device(void);
View file
obs-studio-28.1.2.tar.xz/plugins/obs-filters/CMakeLists.txt -> obs-studio-29.0.0.tar.xz/plugins/obs-filters/CMakeLists.txt
Changed
@@ -129,6 +129,7 @@ color-key-filter.c color-grade-filter.c sharpness-filter.c + eq-filter.c gain-filter.c noise-gate-filter.c mask-filter.c
View file
obs-studio-28.1.2.tar.xz/plugins/obs-filters/data/locale/en-US.ini -> obs-studio-29.0.0.tar.xz/plugins/obs-filters/data/locale/en-US.ini
Changed
@@ -87,6 +87,7 @@ NoiseSuppress.Method.Nvafx.Denoiser="NVIDIA Noise Removal" NoiseSuppress.Method.Nvafx.Dereverb="NVIDIA Room Echo Removal" NoiseSuppress.Method.Nvafx.DenoiserPlusDereverb="NVIDIA Noise Removal + Room Echo Removal" +NoiseSuppress.Method.Nvafx.Deprecation="WARNING: Please upgrade both NVIDIA Video & Audio SDK. Your current version of Audio SDK is outdated." Saturation="Saturation" HueShift="Hue Shift" Amount="Amount" @@ -124,3 +125,11 @@ Greenscreen.Quality="Quality (higher GPU usage, better quality)" Greenscreen.Performance="Performance (lower GPU usage, good quality)" Greenscreen.Threshold="Threshold" +Greenscreen.Deprecation="WARNING: Please upgrade both NVIDIA Video & Audio SDK. Your current version of Video SDK is outdated." +Greenscreen.Processing="Mask refresh frequency in frames" +Greenscreen.Processing.Hint="This alleviates GPU load by generating a mask every N frames only (2 on default)." +Upward.Compressor="Upward Compressor" +3BandEq="3-Band Equalizer" +3BandEq.low="Low" +3BandEq.mid="Mid" +3BandEq.high="High"
View file
obs-studio-29.0.0.tar.xz/plugins/obs-filters/eq-filter.c
Added
@@ -0,0 +1,161 @@ +#include <media-io/audio-math.h> +#include <util/circlebuf.h> +#include <util/darray.h> +#include <obs-module.h> + +#include <math.h> + +#define LOW_FREQ 800.0f +#define HIGH_FREQ 5000.0f + +struct eq_channel_state { + float lf_delay0; + float lf_delay1; + float lf_delay2; + float lf_delay3; + + float hf_delay0; + float hf_delay1; + float hf_delay2; + float hf_delay3; + + float sample_delay1; + float sample_delay2; + float sample_delay3; +}; + +struct eq_data { + obs_source_t *context; + size_t channels; + struct eq_channel_state eqsMAX_AUDIO_CHANNELS; + float lf; + float hf; + float low_gain; + float mid_gain; + float high_gain; +}; + +static const char *eq_name(void *unused) +{ + UNUSED_PARAMETER(unused); + return obs_module_text("3BandEq"); +} + +static void eq_update(void *data, obs_data_t *settings) +{ + struct eq_data *eq = data; + eq->low_gain = db_to_mul((float)obs_data_get_double(settings, "low")); + eq->mid_gain = db_to_mul((float)obs_data_get_double(settings, "mid")); + eq->high_gain = db_to_mul((float)obs_data_get_double(settings, "high")); +} + +static void eq_defaults(obs_data_t *defaults) +{ + obs_data_set_default_double(defaults, "low", 0.0); + obs_data_set_default_double(defaults, "mid", 0.0); + obs_data_set_default_double(defaults, "high", 0.0); +} + +static obs_properties_t *eq_properties(void *unused) +{ + obs_properties_t *props = obs_properties_create(); + obs_property_t *p; + +#define make_db_slider(name) \ + p = obs_properties_add_float_slider(props, name, \ + obs_module_text("3BandEq." name), \ + -20.0f, 20.0, 0.1); \ + obs_property_float_set_suffix(p, " dB"); + + make_db_slider("high"); + make_db_slider("mid"); + make_db_slider("low"); +#undef make_db_slider + + UNUSED_PARAMETER(unused); + return props; +} + +static void *eq_create(obs_data_t *settings, obs_source_t *filter) +{ + struct eq_data *eq = bzalloc(sizeof(*eq)); + eq->channels = audio_output_get_channels(obs_get_audio()); + eq->context = filter; + + float freq = (float)audio_output_get_sample_rate(obs_get_audio()); + eq->lf = 2.0f * sinf(M_PI * LOW_FREQ / freq); + eq->hf = 2.0f * sinf(M_PI * HIGH_FREQ / freq); + + eq_update(eq, settings); + return eq; +} + +static void eq_destroy(void *data) +{ + struct eq_data *eq = data; + bfree(eq); +} + +#define EQ_EPSILON (1.0f / 4294967295.0f) + +static inline float eq_process(struct eq_data *eq, struct eq_channel_state *c, + float sample) +{ + float l, m, h; + + c->lf_delay0 += eq->lf * (sample - c->lf_delay0) + EQ_EPSILON; + c->lf_delay1 += eq->lf * (c->lf_delay0 - c->lf_delay1); + c->lf_delay2 += eq->lf * (c->lf_delay1 - c->lf_delay2); + c->lf_delay3 += eq->lf * (c->lf_delay2 - c->lf_delay3); + + l = c->lf_delay3; + + c->hf_delay0 += eq->hf * (sample - c->hf_delay0) + EQ_EPSILON; + c->hf_delay1 += eq->hf * (c->hf_delay0 - c->hf_delay1); + c->hf_delay2 += eq->hf * (c->hf_delay1 - c->hf_delay2); + c->hf_delay3 += eq->hf * (c->hf_delay2 - c->hf_delay3); + + h = c->sample_delay3 - c->hf_delay3; + m = c->sample_delay3 - (h + l); + + l *= eq->low_gain; + m *= eq->mid_gain; + h *= eq->high_gain; + + c->sample_delay3 = c->sample_delay2; + c->sample_delay2 = c->sample_delay1; + c->sample_delay1 = sample; + + return l + m + h; +} + +static struct obs_audio_data *eq_filter_audio(void *data, + struct obs_audio_data *audio) +{ + struct eq_data *eq = data; + const uint32_t frames = audio->frames; + + for (size_t c = 0; c < eq->channels; c++) { + float *adata = (float *)audio->datac; + struct eq_channel_state *channel = &eq->eqsc; + + for (size_t i = 0; i < frames; i++) { + adatai = eq_process(eq, channel, adatai); + } + } + + return audio; +} + +struct obs_source_info eq_filter = { + .id = "basic_eq_filter", + .type = OBS_SOURCE_TYPE_FILTER, + .output_flags = OBS_SOURCE_AUDIO, + .get_name = eq_name, + .create = eq_create, + .destroy = eq_destroy, + .update = eq_update, + .filter_audio = eq_filter_audio, + .get_defaults = eq_defaults, + .get_properties = eq_properties, +};
View file
obs-studio-28.1.2.tar.xz/plugins/obs-filters/expander-filter.c -> obs-studio-29.0.0.tar.xz/plugins/obs-filters/expander-filter.c
Changed
@@ -10,8 +10,8 @@ /* -------------------------------------------------------- */ -#define do_log(level, format, ...) \ - blog(level, "expander: '%s' " format, \ +#define do_log(level, format, ...) \ + blog(level, "expander/gate/upward compressor: '%s' " format, \ obs_source_get_name(cd->context), ##__VA_ARGS__) #define warn(format, ...) do_log(LOG_WARNING, format, ##__VA_ARGS__) @@ -51,6 +51,8 @@ #define MIN_RATIO 1.0f #define MAX_RATIO 20.0f +#define MIN_RATIO_UPW 0.0f +#define MAX_RATIO_UPW 1.0f #define MIN_THRESHOLD_DB -60.0f #define MAX_THRESHOLD_DB 0.0f #define MIN_OUTPUT_GAIN_DB -32.0f @@ -87,11 +89,12 @@ bool is_gate; float *runaverageMAX_AUDIO_CHANNELS; size_t runaverage_len; - float *gaindBMAX_AUDIO_CHANNELS; - size_t gaindB_len; - float gaindB_bufMAX_AUDIO_CHANNELS; + float *gain_dbMAX_AUDIO_CHANNELS; + size_t gain_db_len; + float gain_db_bufMAX_AUDIO_CHANNELS; float *env_in; size_t env_in_len; + bool is_upwcomp; }; enum { @@ -125,12 +128,12 @@ cd->env_in = brealloc(cd->env_in, cd->env_in_len * sizeof(float)); } -static void resize_gaindB_buffer(struct expander_data *cd, size_t len) +static void resize_gain_db_buffer(struct expander_data *cd, size_t len) { - cd->gaindB_len = len; + cd->gain_db_len = len; for (int i = 0; i < MAX_AUDIO_CHANNELS; i++) - cd->gaindBi = - brealloc(cd->gaindBi, cd->gaindB_len * sizeof(float)); + cd->gain_dbi = brealloc(cd->gain_dbi, + cd->gain_db_len * sizeof(float)); } static inline float gain_coefficient(uint32_t sample_rate, float time) @@ -144,6 +147,12 @@ return obs_module_text("Expander"); } +static const char *upward_compressor_name(void *unused) +{ + UNUSED_PARAMETER(unused); + return obs_module_text("Upward.Compressor"); +} + static void expander_defaults(obs_data_t *s) { const char *presets = obs_data_get_string(s, S_PRESETS); @@ -162,21 +171,33 @@ obs_data_set_default_string(s, S_DETECTOR, "RMS"); } +static void upward_compressor_defaults(obs_data_t *s) +{ + obs_data_set_default_double(s, S_RATIO, 0.5); + obs_data_set_default_double(s, S_THRESHOLD, -20.0f); + obs_data_set_default_int(s, S_ATTACK_TIME, 10); + obs_data_set_default_int(s, S_RELEASE_TIME, 50); + obs_data_set_default_double(s, S_OUTPUT_GAIN, 0.0); + obs_data_set_default_string(s, S_DETECTOR, "RMS"); +} + static void expander_update(void *data, obs_data_t *s) { struct expander_data *cd = data; - const char *presets = obs_data_get_string(s, S_PRESETS); - if (strcmp(presets, "expander") == 0 && cd->is_gate) { - obs_data_clear(s); - obs_data_set_string(s, S_PRESETS, "expander"); - expander_defaults(s); - cd->is_gate = false; - } - if (strcmp(presets, "gate") == 0 && !cd->is_gate) { - obs_data_clear(s); - obs_data_set_string(s, S_PRESETS, "gate"); - expander_defaults(s); - cd->is_gate = true; + if (!cd->is_upwcomp) { + const char *presets = obs_data_get_string(s, S_PRESETS); + if (strcmp(presets, "expander") == 0 && cd->is_gate) { + obs_data_clear(s); + obs_data_set_string(s, S_PRESETS, "expander"); + expander_defaults(s); + cd->is_gate = false; + } + if (strcmp(presets, "gate") == 0 && !cd->is_gate) { + obs_data_clear(s); + obs_data_set_string(s, S_PRESETS, "gate"); + expander_defaults(s); + cd->is_gate = true; + } } const uint32_t sample_rate = @@ -213,28 +234,41 @@ resize_runaverage_buffer(cd, sample_len); if (cd->env_in_len == 0) resize_env_in_buffer(cd, sample_len); - if (cd->gaindB_len == 0) - resize_gaindB_buffer(cd, sample_len); + if (cd->gain_db_len == 0) + resize_gain_db_buffer(cd, sample_len); } -static void *expander_create(obs_data_t *settings, obs_source_t *filter) +static void *compressor_expander_create(obs_data_t *settings, + obs_source_t *filter, + bool is_compressor) { struct expander_data *cd = bzalloc(sizeof(struct expander_data)); cd->context = filter; for (int i = 0; i < MAX_AUDIO_CHANNELS; i++) { cd->runavei = 0; cd->envelopei = 0; - cd->gaindB_bufi = 0; + cd->gain_db_bufi = 0; } cd->is_gate = false; const char *presets = obs_data_get_string(settings, S_PRESETS); if (strcmp(presets, "gate") == 0) cd->is_gate = true; - + cd->is_upwcomp = is_compressor; expander_update(cd, settings); return cd; } +static void *expander_create(obs_data_t *settings, obs_source_t *filter) +{ + return compressor_expander_create(settings, filter, false); +} + +static void *upward_compressor_create(obs_data_t *settings, + obs_source_t *filter) +{ + return compressor_expander_create(settings, filter, true); +} + static void expander_destroy(void *data) { struct expander_data *cd = data; @@ -242,7 +276,7 @@ for (int i = 0; i < MAX_AUDIO_CHANNELS; i++) { bfree(cd->envelope_bufi); bfree(cd->runaveragei); - bfree(cd->gaindBi); + bfree(cd->gain_dbi); } bfree(cd->env_in); bfree(cd); @@ -304,59 +338,93 @@ } } +static inline void process_sample(size_t idx, float *samples, float *env_buf, + float *gain_db, bool is_upwcomp, + float channel_gain, float threshold, + float slope, float attack_gain, + float inv_attack_gain, float release_gain, + float inv_release_gain, float output_gain) +{ + /* --------------------------------- */ + /* gain stage of expansion */ + + float env_db = mul_to_db(env_bufidx); + float diff = threshold - env_db; + + if (is_upwcomp && env_db <= -60.0f) + diff = 0.0f; + + float gain = diff > 0.0f ? fmaxf(slope * diff, -60.0f) : 0.0f; + float prev_gain = gain_dbidx - 1; + + /* --------------------------------- */ + /* ballistics (attack/release) */ + + if (idx > 0) { + if (gain > prev_gain) + gain_dbidx = attack_gain * prev_gain + + inv_attack_gain * gain; + else + gain_dbidx = release_gain * prev_gain + + inv_release_gain * gain; + } else { + if (gain > channel_gain) + gain_dbidx = attack_gain * channel_gain + + inv_attack_gain * gain; + else + gain_dbidx = release_gain * channel_gain + + inv_release_gain * gain; + } + + /* --------------------------------- */ + /* output */ + + float min_val = + is_upwcomp ? fminf(diff, threshold - mul_to_db(samplesidx)) + : 0.0f; + gain = db_to_mul(fminf(min_val, gain_dbidx)); + + // above threshold, don't process expander nor upward compressor + if (threshold - env_db <= 0) + gain = 1.0f; + + samplesidx *= gain * output_gain; +} + // gain stage and ballistics in dB domain static inline void process_expansion(struct expander_data *cd, float **samples, uint32_t num_samples) { const float attack_gain = cd->attack_gain; const float release_gain = cd->release_gain; + const float inv_attack_gain = 1.0f - attack_gain; + const float inv_release_gain = 1.0f - release_gain; + const float threshold = cd->threshold; + const float slope = cd->slope; + const float output_gain = cd->output_gain; + const bool is_upwcomp = cd->is_upwcomp; - if (cd->gaindB_len < num_samples) - resize_gaindB_buffer(cd, num_samples); - for (int i = 0; i < MAX_AUDIO_CHANNELS; i++) - memset(cd->gaindBi, 0, - num_samples * sizeof(cd->gaindBi0)); + if (cd->gain_db_len < num_samples) + resize_gain_db_buffer(cd, num_samples); + + for (size_t i = 0; i < cd->num_channels; i++) + memset(cd->gain_dbi, 0, + num_samples * sizeof(cd->gain_dbi0)); for (size_t chan = 0; chan < cd->num_channels; chan++) { - for (size_t i = 0; i < num_samples; ++i) { - // gain stage of expansion - float env_db = mul_to_db(cd->envelope_bufchani); - float gain = - cd->threshold - env_db > 0.0f - ? fmaxf(cd->slope * (cd->threshold - - env_db), - -60.0f) - : 0.0f; - // ballistics (attack/release) - if (i > 0) { - if (gain > cd->gaindBchani - 1) - cd->gaindBchani = - attack_gain * - cd->gaindBchani - 1 + - (1.0f - attack_gain) * gain; - else - cd->gaindBchani = - release_gain * - cd->gaindBchani - 1 + - (1.0f - release_gain) * gain; - } else { - if (gain > cd->gaindB_bufchan) - cd->gaindBchani = - attack_gain * - cd->gaindB_bufchan + - (1.0f - attack_gain) * gain; - else - cd->gaindBchani = - release_gain * - cd->gaindB_bufchan + - (1.0f - release_gain) * gain; - } + float *channel_samples = sampleschan; + float *env_buf = cd->envelope_bufchan; + float *gain_db = cd->gain_dbchan; + float channel_gain = cd->gain_db_bufchan; - gain = db_to_mul(fminf(0, cd->gaindBchani)); - if (sampleschan) - sampleschani *= gain * cd->output_gain; + for (size_t i = 0; i < num_samples; ++i) { + process_sample(i, channel_samples, env_buf, gain_db, + is_upwcomp, channel_gain, threshold, + slope, attack_gain, inv_attack_gain, + release_gain, inv_release_gain, + output_gain); } - cd->gaindB_bufchan = cd->gaindBchannum_samples - 1; + cd->gain_db_bufchan = gain_dbnum_samples - 1; } } @@ -376,28 +444,25 @@ return audio; } -static bool presets_changed(obs_properties_t *props, obs_property_t *prop, - obs_data_t *settings) -{ - UNUSED_PARAMETER(props); - UNUSED_PARAMETER(prop); - UNUSED_PARAMETER(settings); - return true; -} - static obs_properties_t *expander_properties(void *data) { + struct expander_data *cd = data; obs_properties_t *props = obs_properties_create(); obs_property_t *p; + if (!cd->is_upwcomp) { + obs_property_t *presets = obs_properties_add_list( + props, S_PRESETS, TEXT_PRESETS, OBS_COMBO_TYPE_LIST, + OBS_COMBO_FORMAT_STRING); + obs_property_list_add_string(presets, TEXT_PRESETS_EXP, + "expander"); + obs_property_list_add_string(presets, TEXT_PRESETS_GATE, + "gate"); + } - obs_property_t *presets = obs_properties_add_list( - props, S_PRESETS, TEXT_PRESETS, OBS_COMBO_TYPE_LIST, - OBS_COMBO_FORMAT_STRING); - obs_property_list_add_string(presets, TEXT_PRESETS_EXP, "expander"); - obs_property_list_add_string(presets, TEXT_PRESETS_GATE, "gate"); - obs_property_set_modified_callback(presets, presets_changed); - p = obs_properties_add_float_slider(props, S_RATIO, TEXT_RATIO, - MIN_RATIO, MAX_RATIO, 0.1); + p = obs_properties_add_float_slider( + props, S_RATIO, TEXT_RATIO, + !cd->is_upwcomp ? MIN_RATIO : MIN_RATIO_UPW, + !cd->is_upwcomp ? MAX_RATIO : MAX_RATIO_UPW, 0.1); obs_property_float_set_suffix(p, ":1"); p = obs_properties_add_float_slider(props, S_THRESHOLD, TEXT_THRESHOLD, MIN_THRESHOLD_DB, MAX_THRESHOLD_DB, @@ -416,13 +481,13 @@ MIN_OUTPUT_GAIN_DB, MAX_OUTPUT_GAIN_DB, 0.1); obs_property_float_set_suffix(p, " dB"); - obs_property_t *detect = obs_properties_add_list( - props, S_DETECTOR, TEXT_DETECTOR, OBS_COMBO_TYPE_LIST, - OBS_COMBO_FORMAT_STRING); - obs_property_list_add_string(detect, TEXT_RMS, "RMS"); - obs_property_list_add_string(detect, TEXT_PEAK, "peak"); - - UNUSED_PARAMETER(data); + if (!cd->is_upwcomp) { + obs_property_t *detect = obs_properties_add_list( + props, S_DETECTOR, TEXT_DETECTOR, OBS_COMBO_TYPE_LIST, + OBS_COMBO_FORMAT_STRING); + obs_property_list_add_string(detect, TEXT_RMS, "RMS"); + obs_property_list_add_string(detect, TEXT_PEAK, "peak"); + } return props; } @@ -438,3 +503,16 @@ .get_defaults = expander_defaults, .get_properties = expander_properties, }; + +struct obs_source_info upward_compressor_filter = { + .id = "upward_compressor_filter", + .type = OBS_SOURCE_TYPE_FILTER, + .output_flags = OBS_SOURCE_AUDIO, + .get_name = upward_compressor_name, + .create = upward_compressor_create, + .destroy = expander_destroy, + .update = expander_update, + .filter_audio = expander_filter_audio, + .get_defaults = upward_compressor_defaults, + .get_properties = expander_properties, +};
View file
obs-studio-28.1.2.tar.xz/plugins/obs-filters/noise-suppress-filter.c -> obs-studio-29.0.0.tar.xz/plugins/obs-filters/noise-suppress-filter.c
Changed
@@ -59,6 +59,8 @@ #define TEXT_METHOD_NVAFX_DEREVERB MT_("NoiseSuppress.Method.Nvafx.Dereverb") #define TEXT_METHOD_NVAFX_DEREVERB_DENOISER \ MT_("NoiseSuppress.Method.Nvafx.DenoiserPlusDereverb") +#define TEXT_METHOD_NVAFX_DEPRECATION \ + MT_("NoiseSuppress.Method.Nvafx.Deprecation") #define MAX_PREPROC_CHANNELS 8 @@ -623,9 +625,23 @@ bool load_nvafx(void) { #ifdef LIBNVAFX_ENABLED + unsigned int version = get_lib_version(); + uint8_t major = (version >> 24) & 0xff; + uint8_t minor = (version >> 16) & 0x00ff; + uint8_t build = (version >> 8) & 0x0000ff; + uint8_t revision = (version >> 0) & 0x000000ff; + if (version) { + blog(LOG_INFO, + "noise suppress: NVIDIA AUDIO FX version: %i.%i.%i.%i", + major, minor, build, revision); + if (version < (MIN_AFX_SDK_VERSION)) { + blog(LOG_INFO, + "noise suppress: NVIDIA AUDIO Effects SDK is outdated. Please update both audio & video SDK."); + } + } if (!load_lib()) { blog(LOG_INFO, - "noise suppress: NVIDIA RTX denoiser disabled, redistributable not found"); + "noise suppress: NVIDIA denoiser disabled, redistributable not found or could not be loaded."); return false; } @@ -699,10 +715,10 @@ if (err != NVAFX_STATUS_SUCCESS) { if (err == NVAFX_STATUS_GPU_UNSUPPORTED) { blog(LOG_INFO, - "noise suppress: NVIDIA RTX AUDIO FX disabled: unsupported GPU"); + "noise suppress: NVIDIA AUDIO FX disabled: unsupported GPU"); } else { blog(LOG_ERROR, - "noise suppress: NVIDIA RTX AUDIO FX disabled, error %i", + "noise suppress: NVIDIA AUDIO FX disabled, error %i", err); } goto unload_everything; @@ -711,18 +727,18 @@ err = NvAFX_DestroyEffect(h); if (err != NVAFX_STATUS_SUCCESS) { blog(LOG_ERROR, - "noise suppress: NVIDIA RTX AUDIO FX disabled, error %i", + "noise suppress: NVIDIA AUDIO FX disabled, error %i", err); goto unload_everything; } nvafx_loaded = true; - blog(LOG_INFO, "noise suppress: NVIDIA RTX AUDIO FX enabled"); + blog(LOG_INFO, "noise suppress: NVIDIA AUDIO FX enabled"); return true; cuda_errors: blog(LOG_ERROR, - "noise suppress: NVIDIA RTX AUDIO FX disabled, CUDA error %i", + "noise suppress: NVIDIA AUDIO FX disabled, CUDA error %i", cudaerr); unload_everything: release_lib(); @@ -1205,10 +1221,19 @@ #endif #ifdef LIBNVAFX_ENABLED - obs_properties_add_float_slider(ppts, S_NVAFX_INTENSITY, - TEXT_NVAFX_INTENSITY, 0.0f, 1.0f, - 0.01f); - + if (ng->nvafx_enabled) { + obs_properties_add_float_slider(ppts, S_NVAFX_INTENSITY, + TEXT_NVAFX_INTENSITY, 0.0f, + 1.0f, 0.01f); + } + unsigned int version = get_lib_version(); + if (version < (MIN_AFX_SDK_VERSION)) { + obs_property_t *warning = obs_properties_add_text( + ppts, "deprecation", NULL, OBS_TEXT_INFO); + obs_property_text_set_info_type(warning, OBS_TEXT_INFO_WARNING); + obs_property_set_long_description( + warning, TEXT_METHOD_NVAFX_DEPRECATION); + } #if defined(LIBRNNOISE_ENABLED) && defined(LIBSPEEXDSP_ENABLED) if (!nvafx_loaded) { obs_property_list_item_disable(method, 2, true);
View file
obs-studio-28.1.2.tar.xz/plugins/obs-filters/nvafx-load.h -> obs-studio-29.0.0.tar.xz/plugins/obs-filters/nvafx-load.h
Changed
@@ -4,10 +4,12 @@ #include <stddef.h> #include <stdint.h> #include <util/platform.h> +#include <util/windows/win-version.h> #define NVAFX_API #ifdef LIBNVAFX_ENABLED +#define MIN_AFX_SDK_VERSION 1 << 24 | 2 << 16 | 13 << 0 static HMODULE nv_audiofx = NULL; static HMODULE nv_cuda = NULL; @@ -307,4 +309,18 @@ nv_cuda = LoadLibrary(L"nvcuda.dll"); return !!nv_audiofx && !!nv_cuda; } + +static unsigned int get_lib_version(void) +{ + char pathMAX_PATH; + if (!nvafx_get_sdk_path(path, sizeof(path))) + return 0; + + SetDllDirectoryA(path); + struct win_version_info nto_ver = {0}; + get_dll_ver(L"NVAudioEffects.dll", &nto_ver); + unsigned int version = nto_ver.major << 24 | nto_ver.minor << 16 | + nto_ver.build << 8 | nto_ver.revis << 0; + return version; +} #endif
View file
obs-studio-28.1.2.tar.xz/plugins/obs-filters/nvidia-greenscreen-filter.c -> obs-studio-29.0.0.tar.xz/plugins/obs-filters/nvidia-greenscreen-filter.c
Changed
@@ -6,9 +6,9 @@ #include "nvvfx-load.h" /* -------------------------------------------------------- */ -#define do_log(level, format, ...) \ - blog(level, \ - "NVIDIA RTX AI Greenscreen (Background removal): '%s' " format, \ +#define do_log(level, format, ...) \ + blog(level, \ + "NVIDIA AI Greenscreen (Background removal): '%s' " format, \ obs_source_get_name(filter->context), ##__VA_ARGS__) #define warn(format, ...) do_log(LOG_WARNING, format, ##__VA_ARGS__) @@ -27,14 +27,19 @@ #define S_MODE_PERF 1 #define S_THRESHOLDFX "threshold" #define S_THRESHOLDFX_DEFAULT 1.0 +#define S_PROCESSING "processing_interval" #define MT_ obs_module_text #define TEXT_MODE MT_("Greenscreen.Mode") #define TEXT_MODE_QUALITY MT_("Greenscreen.Quality") #define TEXT_MODE_PERF MT_("Greenscreen.Performance") #define TEXT_MODE_THRESHOLD MT_("Greenscreen.Threshold") +#define TEXT_DEPRECATION MT_("Greenscreen.Deprecation") +#define TEXT_PROCESSING MT_("Greenscreen.Processing") +#define TEXT_PROCESSING_HINT MT_("Greenscreen.Processing.Hint") bool nvvfx_loaded = false; +bool nvvfx_new_sdk = false; struct nv_greenscreen_data { obs_source_t *context; bool images_allocated; @@ -54,6 +59,8 @@ NvCVImage *A_dst_img; // mask img on GPU NvCVImage *dst_img; // mask texture NvCVImage *stage; // planar stage img used for transfer to texture + unsigned int version; + NvVFX_StateObjectHandle stateObjectHandle; /* alpha mask effect */ gs_effect_t *effect; @@ -68,6 +75,13 @@ gs_eparam_t *threshold_param; gs_eparam_t *multiplier_param; float threshold; + + /* Every nth frame is processed through the FX (where n = + * processing_interval) so that the same mask is used for n consecutive + * frames. This is to alleviate the GPU load. Default: 1 (process every frame). + */ + int processing_interval; + int processing_counter; }; static const char *nv_greenscreen_filter_name(void *unused) @@ -89,6 +103,8 @@ error("Error loading AI Greenscreen FX %i", vfxErr); } filter->threshold = (float)obs_data_get_double(settings, S_THRESHOLDFX); + filter->processing_interval = + (int)obs_data_get_int(settings, S_PROCESSING); } static void nv_greenscreen_filter_actual_destroy(void *data) @@ -117,8 +133,13 @@ NvVFX_CudaStreamDestroy(filter->stream); } if (filter->handle) { + if (filter->stateObjectHandle) { + NvVFX_DeallocateState(filter->handle, + filter->stateObjectHandle); + } NvVFX_DestroyEffect(filter->handle); } + if (filter->effect) { obs_enter_graphics(); gs_effect_destroy(filter->effect); @@ -145,6 +166,10 @@ NvVFX_CudaStreamDestroy(filter->stream); } if (filter->handle) { + if (filter->stateObjectHandle) { + NvVFX_DeallocateState(filter->handle, + filter->stateObjectHandle); + } NvVFX_DestroyEffect(filter->handle); } // recreate @@ -410,6 +435,8 @@ filter->initial_render = false; os_atomic_set_bool(&filter->processing_stop, false); filter->handler = NULL; + filter->processing_interval = 1; + filter->processing_counter = 0; /* 1. Create FX */ vfxErr = NvVFX_CreateEffect(NVVFX_FX_GREEN_SCREEN, &filter->handle); @@ -445,13 +472,15 @@ nv_greenscreen_filter_destroy(filter); return NULL; } - /* log sdk version */ - unsigned int version; - if (NvVFX_GetVersion(&version) == NVCV_SUCCESS) { - uint8_t major = (version >> 24) & 0xff; - uint8_t minor = (version >> 16) & 0x00ff; - uint8_t build = (version >> 8) & 0x0000ff; - info("RTX VIDEO FX version: %i.%i.%i", major, minor, build); + /* check sdk version */ + if (NvVFX_GetVersion(&filter->version) == NVCV_SUCCESS) { + uint8_t major = (filter->version >> 24) & 0xff; + uint8_t minor = (filter->version >> 16) & 0x00ff; + uint8_t build = (filter->version >> 8) & 0x0000ff; + uint8_t revision = (filter->version >> 0) & 0x000000ff; + // sanity check + nvvfx_new_sdk = filter->version >= (MIN_VFX_SDK_VERSION) && + nvvfx_new_sdk; } /* 3. Load alpha mask effect. */ @@ -472,6 +501,29 @@ } obs_leave_graphics(); + /* 4. Allocate state for the effect */ + if (nvvfx_new_sdk) { + vfxErr = NvVFX_AllocateState(filter->handle, + &filter->stateObjectHandle); + if (NVCV_SUCCESS != vfxErr) { + const char *errString = + NvCV_GetErrorStringFromCode(vfxErr); + error("Error allocating FX state %i", vfxErr); + nv_greenscreen_filter_destroy(filter); + return NULL; + } + vfxErr = NvVFX_SetStateObjectHandleArray( + filter->handle, NVVFX_STATE, + &filter->stateObjectHandle); + if (NVCV_SUCCESS != vfxErr) { + const char *errString = + NvCV_GetErrorStringFromCode(vfxErr); + error("Error setting FX state %i", vfxErr); + nv_greenscreen_filter_destroy(filter); + return NULL; + } + } + if (!filter->effect) { nv_greenscreen_filter_destroy(filter); return NULL; @@ -486,6 +538,7 @@ static obs_properties_t *nv_greenscreen_filter_properties(void *data) { + struct nv_greenscreen_data *filter = (struct nv_greenscreen_data *)data; obs_properties_t *props = obs_properties_create(); obs_property_t *mode = obs_properties_add_list(props, S_MODE, TEXT_MODE, OBS_COMBO_TYPE_LIST, @@ -494,8 +547,17 @@ obs_property_list_add_int(mode, TEXT_MODE_PERF, S_MODE_PERF); obs_property_t *threshold = obs_properties_add_float_slider( props, S_THRESHOLDFX, TEXT_MODE_THRESHOLD, 0, 1, 0.05); + obs_property_t *partial = obs_properties_add_int_slider( + props, S_PROCESSING, TEXT_PROCESSING, 1, 4, 1); + obs_property_set_long_description(partial, TEXT_PROCESSING_HINT); + unsigned int version = get_lib_version(); + if (version < (MIN_VFX_SDK_VERSION)) { + obs_property_t *warning = obs_properties_add_text( + props, "deprecation", NULL, OBS_TEXT_INFO); + obs_property_text_set_info_type(warning, OBS_TEXT_INFO_WARNING); + obs_property_set_long_description(warning, TEXT_DEPRECATION); + } - UNUSED_PARAMETER(data); return props; } @@ -504,7 +566,9 @@ obs_data_set_default_int(settings, S_MODE, S_MODE_QUALITY); obs_data_set_default_double(settings, S_THRESHOLDFX, S_THRESHOLDFX_DEFAULT); + obs_data_set_default_int(settings, S_PROCESSING, 1); } + static struct obs_source_frame * nv_greenscreen_filter_video(void *data, struct obs_source_frame *frame) { @@ -660,7 +724,7 @@ if (parent && !filter->handler) { filter->handler = obs_source_get_signal_handler(parent); - signal_handler_connect(filter->handler, "update_properties", + signal_handler_connect(filter->handler, "update", nv_greenscreen_filter_reset, filter); } @@ -799,7 +863,14 @@ if (filter->initial_render && filter->images_allocated) { bool draw = true; if (!async || filter->got_new_frame) { - draw = process_texture_greenscreen(filter); + if (filter->processing_counter % + filter->processing_interval == + 0) { + draw = process_texture_greenscreen(filter); + filter->processing_counter = 1; + } else { + filter->processing_counter++; + } filter->got_new_frame = false; } @@ -815,20 +886,46 @@ bool load_nvvfx(void) { + bool old_sdk_loaded = false; + unsigned int version = get_lib_version(); + uint8_t major = (version >> 24) & 0xff; + uint8_t minor = (version >> 16) & 0x00ff; + uint8_t build = (version >> 8) & 0x0000ff; + uint8_t revision = (version >> 0) & 0x000000ff; + if (version) { + blog(LOG_INFO, + "NVIDIA VIDEO FX: NVIDIA VIDEO FX version: %i.%i.%i.%i", + major, minor, build, revision); + if (version < (MIN_VFX_SDK_VERSION)) { + blog(LOG_INFO, + "NVIDIA VIDEO FX: NVIDIA VIDEO Effects SDK is outdated. Please update both audio & video SDK."); + } + } if (!load_nv_vfx_libs()) { blog(LOG_INFO, - "NVIDIA RTX VIDEO FX: FX disabled, redistributable not found."); + "NVIDIA VIDEO FX: FX disabled, redistributable not found or could not be loaded."); return false; } -#define LOAD_SYM_FROM_LIB(sym, lib, dll) \ - if (!(sym = (sym##_t)GetProcAddress(lib, #sym))) { \ - DWORD err = GetLastError(); \ - printf("NVIDIA RTX VIDEO FX: Couldn't load " #sym \ - " from " dll ": %lu (0x%lx)", \ - err, err); \ - release_nv_vfx(); \ - goto unload_everything; \ +#define LOAD_SYM_FROM_LIB(sym, lib, dll) \ + if (!(sym = (sym##_t)GetProcAddress(lib, #sym))) { \ + DWORD err = GetLastError(); \ + printf("NVIDIA VIDEO FX: Couldn't load " #sym " from " dll \ + ": %lu (0x%lx)", \ + err, err); \ + release_nv_vfx(); \ + goto unload_everything; \ + } + +#define LOAD_SYM_FROM_LIB2(sym, lib, dll) \ + if (!(sym = (sym##_t)GetProcAddress(lib, #sym))) { \ + DWORD err = GetLastError(); \ + printf("NVIDIA VIDEO FX: Couldn't load " #sym " from " dll \ + ": %lu (0x%lx)", \ + err, err); \ + nvvfx_new_sdk = false; \ + } else { \ + nvvfx_new_sdk = true; \ } #define LOAD_SYM(sym) LOAD_SYM_FROM_LIB(sym, nv_videofx, "NVVideoEffects.dll") @@ -857,7 +954,9 @@ LOAD_SYM(NvVFX_Load); LOAD_SYM(NvVFX_CudaStreamCreate); LOAD_SYM(NvVFX_CudaStreamDestroy); + old_sdk_loaded = true; #undef LOAD_SYM + #define LOAD_SYM(sym) LOAD_SYM_FROM_LIB(sym, nv_cvimage, "NVCVImage.dll") LOAD_SYM(NvCV_GetErrorStringFromCode); LOAD_SYM(NvCVImage_Init); @@ -885,6 +984,7 @@ LOAD_SYM(NvCVImage_ToD3DColorSpace); LOAD_SYM(NvCVImage_FromD3DColorSpace); #undef LOAD_SYM + #define LOAD_SYM(sym) LOAD_SYM_FROM_LIB(sym, nv_cudart, "cudart64_110.dll") LOAD_SYM(cudaMalloc); LOAD_SYM(cudaStreamSynchronize); @@ -892,6 +992,18 @@ LOAD_SYM(cudaMemcpy); LOAD_SYM(cudaMemsetAsync); #undef LOAD_SYM + +#define LOAD_SYM(sym) LOAD_SYM_FROM_LIB2(sym, nv_videofx, "NVVideoEffects.dll") + LOAD_SYM(NvVFX_SetStateObjectHandleArray); + LOAD_SYM(NvVFX_AllocateState); + LOAD_SYM(NvVFX_DeallocateState); + LOAD_SYM(NvVFX_ResetState); + if (!nvvfx_new_sdk) { + blog(LOG_INFO, + "NVIDIA VIDEO FX: sdk loaded but old redistributable detected; please upgrade."); + } +#undef LOAD_SYM + int err; NvVFX_Handle h = NULL; @@ -900,20 +1012,22 @@ if (err != NVCV_SUCCESS) { if (err == NVCV_ERR_UNSUPPORTEDGPU) { blog(LOG_INFO, - "NVIDIA RTX VIDEO FX: disabled, unsupported GPU"); + "NVIDIA VIDEO FX: disabled, unsupported GPU"); } else { - blog(LOG_ERROR, - "NVIDIA RTX VIDEO FX: disabled, error %i", err); + blog(LOG_ERROR, "NVIDIA VIDEO FX: disabled, error %i", + err); } goto unload_everything; } NvVFX_DestroyEffect(h); nvvfx_loaded = true; - blog(LOG_INFO, "NVIDIA RTX VIDEO FX: enabled, redistributable found"); + blog(LOG_INFO, "NVIDIA VIDEO FX: enabled, redistributable found"); return true; unload_everything: nvvfx_loaded = false; + blog(LOG_INFO, + "NVIDIA VIDEO FX: disabled, redistributable not found"); release_nv_vfx(); return false; }
View file
obs-studio-28.1.2.tar.xz/plugins/obs-filters/nvvfx-load.h -> obs-studio-29.0.0.tar.xz/plugins/obs-filters/nvvfx-load.h
Changed
@@ -6,6 +6,7 @@ #include <stdint.h> #include <util/platform.h> #include <dxgitype.h> +#include <util/windows/win-version.h> #ifdef __cplusplus extern "C" { @@ -38,7 +39,7 @@ #define CUDARTAPI #ifdef LIBNVVFX_ENABLED -// allows for future loading of a second fx +#define MIN_VFX_SDK_VERSION 0 << 24 | 7 << 16 | 1 << 8 | 0 << 0 static HMODULE nv_videofx = NULL; static HMODULE nv_cvimage = NULL; static HMODULE nv_cudart = NULL; @@ -139,8 +140,14 @@ #define NVVFX_CUDA_STREAM "CudaStream" //!< The CUDA stream to use #define NVVFX_CUDA_GRAPH "CudaGraph" //!< Enable CUDA graph to use #define NVVFX_INFO "Info" //!< Get info about the effects -#define NVVFX_SCALE "Scale" //!< Scale factor -#define NVVFX_STRENGTH "Strength" //!< Strength for different filters +#define NVVFX_MAX_INPUT_WIDTH \ + "MaxInputWidth" //!< Maximum width of the input supported +#define NVVFX_MAX_INPUT_HEIGHT \ + "MaxInputHeight" //!< Maximum height of the input supported +#define NVVFX_MAX_NUMBER_STREAMS \ + "MaxNumberStreams" //!< Maximum number of concurrent input streams +#define NVVFX_SCALE "Scale" //!< Scale factor +#define NVVFX_STRENGTH "Strength" //!< Strength for different filters #define NVVFX_STRENGTH_LEVELS "StrengthLevels" //!< Number of strength levels #define NVVFX_MODE "Mode" //!< Mode for different filters #define NVVFX_TEMPORAL "Temporal" //!< Temporal mode: 0=image, 1=video @@ -149,6 +156,8 @@ #define NVVFX_MODEL_BATCH "ModelBatch" #define NVVFX_STATE "State" //!< State variable #define NVVFX_STATE_SIZE "StateSize" //!< Number of bytes needed to store state +#define NVVFX_STATE_COUNT \ + "NumStateObjects" //!< Number of active state object handles //! The format of pixels in an image. typedef enum NvCVImage_PixelFormat { @@ -324,6 +333,8 @@ typedef const char *NvVFX_EffectSelector; typedef const char *NvVFX_ParameterSelector; typedef void *NvVFX_Handle; +/* requires sdk version >= 0.7.0 */ +typedef void *NvVFX_StateObjectHandle; /* nvvfx functions */ typedef NvCV_Status NvVFX_API (*NvVFX_GetVersion_t)(unsigned int *version); @@ -346,6 +357,11 @@ unsigned long long val); typedef NvCV_Status NvVFX_API (*NvVFX_SetObject_t)( NvVFX_Handle effect, NvVFX_ParameterSelector param_name, void *ptr); +/* requires sdk version >= 0.7.0 */ +typedef NvCV_Status NvVFX_API (*NvVFX_SetStateObjectHandleArray_t)( + NvVFX_Handle effect, NvVFX_ParameterSelector param_name, + NvVFX_StateObjectHandle *handle); +/* ----------------------------- */ typedef NvCV_Status NvVFX_API (*NvVFX_SetCudaStream_t)(NvVFX_Handle effect, NvVFX_ParameterSelector param_name, @@ -387,6 +403,17 @@ typedef NvCV_Status NvVFX_API (*NvVFX_CudaStreamCreate_t)(CUstream *stream); typedef NvCV_Status NvVFX_API (*NvVFX_CudaStreamDestroy_t)(CUstream stream); +/* requires sdk version >= 0.7.0 */ +typedef NvCV_Status + NvVFX_API (*NvVFX_AllocateState_t)(NvVFX_Handle effect, + NvVFX_StateObjectHandle *handle); +typedef NvCV_Status + NvVFX_API (*NvVFX_DeallocateState_t)(NvVFX_Handle effect, + NvVFX_StateObjectHandle handle); +typedef NvCV_Status + NvVFX_API (*NvVFX_ResetState_t)(NvVFX_Handle effect, + NvVFX_StateObjectHandle handle); + /* NvCVImage functions */ typedef NvCV_Status NvCV_API (*NvCVImage_Init_t)( NvCVImage *im, unsigned width, unsigned height, int pitch, void *pixels, @@ -643,6 +670,12 @@ static NvVFX_CudaStreamCreate_t NvVFX_CudaStreamCreate = NULL; static NvVFX_CudaStreamDestroy_t NvVFX_CudaStreamDestroy = NULL; +/* nvvfx sdk >= 0.7.0 */ +static NvVFX_SetStateObjectHandleArray_t NvVFX_SetStateObjectHandleArray = NULL; +static NvVFX_AllocateState_t NvVFX_AllocateState = NULL; +static NvVFX_DeallocateState_t NvVFX_DeallocateState = NULL; +static NvVFX_ResetState_t NvVFX_ResetState = NULL; + /*nvcvimage */ static NvCVImage_Init_t NvCVImage_Init = NULL; static NvCVImage_InitView_t NvCVImage_InitView = NULL; @@ -707,6 +740,10 @@ NvVFX_SetString = NULL; NvVFX_SetU32 = NULL; NvVFX_SetU64 = NULL; + NvVFX_SetStateObjectHandleArray = NULL; + NvVFX_AllocateState = NULL; + NvVFX_DeallocateState = NULL; + NvVFX_ResetState = NULL; if (nv_videofx) { FreeLibrary(nv_videofx); nv_videofx = NULL; @@ -761,8 +798,7 @@ size_t max_len = sizeof(path) / sizeof(char); snprintf(buffer, max_len, - "%s\\NVIDIA Corporation\\NVIDIA Video Effects\\", - path); + "%s\\NVIDIA Corporation\\NVIDIA Video Effects", path); } } @@ -771,6 +807,7 @@ char fullPathMAX_PATH; nvvfx_get_sdk_path(fullPath, MAX_PATH); SetDllDirectoryA(fullPath); + nv_videofx = LoadLibrary(L"NVVideoEffects.dll"); nv_cvimage = LoadLibrary(L"NVCVImage.dll"); nv_cudart = LoadLibrary(L"cudart64_110.dll"); @@ -778,6 +815,18 @@ return !!nv_videofx && !!nv_cvimage && !!nv_cudart; } +static unsigned int get_lib_version(void) +{ + char pathMAX_PATH; + nvvfx_get_sdk_path(path, sizeof(path)); + + SetDllDirectoryA(path); + struct win_version_info nto_ver = {0}; + get_dll_ver(L"NVVideoEffects.dll", &nto_ver); + unsigned int version = nto_ver.major << 24 | nto_ver.minor << 16 | + nto_ver.build << 8 | nto_ver.revis << 0; + return version; +} #endif #ifdef __cplusplus
View file
obs-studio-28.1.2.tar.xz/plugins/obs-filters/obs-filters.c -> obs-studio-29.0.0.tar.xz/plugins/obs-filters/obs-filters.c
Changed
@@ -11,6 +11,7 @@ extern struct obs_source_info mask_filter_v2; extern struct obs_source_info crop_filter; extern struct obs_source_info gain_filter; +extern struct obs_source_info eq_filter; extern struct obs_source_info hdr_tonemap_filter; extern struct obs_source_info color_filter; extern struct obs_source_info color_filter_v2; @@ -36,6 +37,7 @@ extern struct obs_source_info compressor_filter; extern struct obs_source_info limiter_filter; extern struct obs_source_info expander_filter; +extern struct obs_source_info upward_compressor_filter; extern struct obs_source_info luma_key_filter; extern struct obs_source_info luma_key_filter_v2; #ifdef LIBNVVFX_ENABLED @@ -50,6 +52,7 @@ obs_register_source(&mask_filter_v2); obs_register_source(&crop_filter); obs_register_source(&gain_filter); + obs_register_source(&eq_filter); obs_register_source(&hdr_tonemap_filter); obs_register_source(&color_filter); obs_register_source(&color_filter_v2); @@ -77,6 +80,7 @@ obs_register_source(&compressor_filter); obs_register_source(&limiter_filter); obs_register_source(&expander_filter); + obs_register_source(&upward_compressor_filter); obs_register_source(&luma_key_filter); obs_register_source(&luma_key_filter_v2); #ifdef LIBNVVFX_ENABLED
View file
obs-studio-28.1.2.tar.xz/plugins/obs-filters/scale-filter.c -> obs-studio-29.0.0.tar.xz/plugins/obs-filters/scale-filter.c
Changed
@@ -540,7 +540,8 @@ for (size_t i = 0; i < NUM_DOWNSCALES; i++) { char str32; - snprintf(str, 32, "%dx%d", downscalesi.cx, downscalesi.cy); + snprintf(str, sizeof(str), "%dx%d", downscalesi.cx, + downscalesi.cy); obs_property_list_add_string(p, str, str); }
View file
obs-studio-28.1.2.tar.xz/plugins/obs-outputs/librtmp/amf.c -> obs-studio-29.0.0.tar.xz/plugins/obs-outputs/librtmp/amf.c
Changed
@@ -831,7 +831,7 @@ if (name.av_len > 18) name.av_len = 18; - snprintf(strRes, 255, "Name: %18.*s, ", name.av_len, name.av_val); + snprintf(strRes, sizeof(strRes), "Name: %18.*s, ", name.av_len, name.av_val); if (prop->p_type == AMF_OBJECT) { @@ -855,22 +855,22 @@ switch (prop->p_type) { case AMF_NUMBER: - snprintf(str, 255, "NUMBER:\t%.2f", prop->p_vu.p_number); + snprintf(str, sizeof(str), "NUMBER:\t%.2f", prop->p_vu.p_number); break; case AMF_BOOLEAN: - snprintf(str, 255, "BOOLEAN:\t%s", + snprintf(str, sizeof(str), "BOOLEAN:\t%s", prop->p_vu.p_number != 0.0 ? "TRUE" : "FALSE"); break; case AMF_STRING: - snprintf(str, 255, "STRING:\t%.*s", prop->p_vu.p_aval.av_len, + snprintf(str, sizeof(str), "STRING:\t%.*s", prop->p_vu.p_aval.av_len, prop->p_vu.p_aval.av_val); break; case AMF_DATE: - snprintf(str, 255, "DATE:\ttimestamp: %.2f, UTC offset: %d", + snprintf(str, sizeof(str), "DATE:\ttimestamp: %.2f, UTC offset: %d", prop->p_vu.p_number, prop->p_UTCoffset); break; default: - snprintf(str, 255, "INVALID TYPE 0x%02x", (unsigned char)prop->p_type); + snprintf(str, sizeof(str), "INVALID TYPE 0x%02x", (unsigned char)prop->p_type); } RTMP_Log(RTMP_LOGDEBUG, "Property: <%s%s>", strRes, str);
View file
obs-studio-28.1.2.tar.xz/plugins/obs-outputs/librtmp/hashswf.c -> obs-studio-29.0.0.tar.xz/plugins/obs-outputs/librtmp/hashswf.c
Changed
@@ -152,12 +152,12 @@ if (sb.sb_socket == INVALID_SOCKET) return HTTPRES_LOST_CONNECTION; i = - sprintf(sb.sb_buf, + snprintf(sb.sb_buf, RTMP_BUFFER_CACHE_SIZE, "GET %s HTTP/1.0\r\nUser-Agent: %s\r\nHost: %s\r\nReferer: %.*s\r\n", path, AGENT, host, (int)(path - url + 1), url); if (http->date0) - i += sprintf(sb.sb_buf + i, "If-Modified-Since: %s\r\n", http->date); - i += sprintf(sb.sb_buf + i, "\r\n"); + i += snprintf(sb.sb_buf + i, RTMP_BUFFER_CACHE_SIZE, "If-Modified-Since: %s\r\n", http->date); + i += snprintf(sb.sb_buf + i, RTMP_BUFFER_CACHE_SIZE, "\r\n"); if (connect (sb.sb_socket, (struct sockaddr *)&sa, sizeof(struct sockaddr)) < 0) @@ -455,12 +455,12 @@ * Weekday, DD-MMM-YYYY HH:MM:SS GMT */ static void -strtime(time_t * t, char *s) +strtime(time_t * t, char *s, size_t size) { struct tm *tm; tm = gmtime((time_t *) t); - sprintf(s, "%s, %02d %s %d %02d:%02d:%02d GMT", + snprintf(s, size, "%s, %02d %s %d %02d:%02d:%02d GMT", daystm->tm_wday, tm->tm_mday, monthtabtm->tm_mon, tm->tm_year + 1900, tm->tm_hour, tm->tm_min, tm->tm_sec); } @@ -516,8 +516,9 @@ * These fields must be present in this order. All fields * besides URL are fixed size. */ - path = malloc(hpre.av_len + home.av_len + sizeof(DIRSEP ".swfinfo")); - sprintf(path, "%s%s" DIRSEP ".swfinfo", hpre.av_val, home.av_val); + size_t path_size = hpre.av_len + home.av_len + sizeof(DIRSEP ".swfinfo"); + path = malloc(path_size); + snprintf(path, path_size, "%s%s" DIRSEP ".swfinfo", hpre.av_val, home.av_val); f = fopen(path, "r+"); while (f) @@ -651,7 +652,7 @@ fprintf(f, "url: %.*s\n", i, url); } - strtime(&cnow, cctim); + strtime(&cnow, cctim, sizeof(cctim)); fprintf(f, "ctim: %s\n", cctim); if (!in.first)
View file
obs-studio-28.1.2.tar.xz/plugins/obs-outputs/librtmp/rtmp.c -> obs-studio-29.0.0.tar.xz/plugins/obs-outputs/librtmp/rtmp.c
Changed
@@ -488,7 +488,7 @@ r->Link.curStreamIdx = 0; r->Link.nStreams = 0; r->Link.receiveTimeout = 30; - r->Link.sendTimeout = 6; + r->Link.sendTimeout = 15; r->Link.swfAge = 30; } @@ -781,7 +781,7 @@ char portStr8; - sprintf(portStr, "%d", port); + snprintf(portStr, sizeof(portStr), "%d", port); int err = getaddrinfo(hostname, portStr, &hints, &result); @@ -2623,12 +2623,12 @@ static const AVal av_authmod_adobe = AVC("authmod=adobe"); static const AVal av_authmod_llnw = AVC("authmod=llnw"); -static void hexenc(unsigned char *inbuf, int len, char *dst) +static void hexenc(unsigned char *inbuf, int len, char *dst, size_t size) { char *ptr = dst; while(len--) { - sprintf(ptr, "%02x", *inbuf++); + snprintf(ptr, size, "%02x", *inbuf++); ptr += 2; } *ptr = '\0'; @@ -2676,8 +2676,9 @@ } else if(r->Link.pubUser.av_len && r->Link.pubPasswd.av_len) { - pubToken.av_val = malloc(r->Link.pubUser.av_len + av_authmod_adobe.av_len + 8); - pubToken.av_len = sprintf(pubToken.av_val, "?%s&user=%s", + size_t val_size = r->Link.pubUser.av_len + av_authmod_adobe.av_len + 8; + pubToken.av_val = malloc(val_size); + pubToken.av_len = snprintf(pubToken.av_val, val_size, "?%s&user=%s", av_authmod_adobe.av_val, r->Link.pubUser.av_val); RTMP_Log(RTMP_LOGDEBUG, "%s, pubToken1: %s", __FUNCTION__, pubToken.av_val); @@ -2777,8 +2778,9 @@ RTMP_Log(RTMP_LOGDEBUG, "%s, b64(md5_2) = %s", __FUNCTION__, response); /* have all hashes, create auth token for the end of app */ - pubToken.av_val = malloc(32 + B64INT_LEN + B64DIGEST_LEN + opaque.av_len); - pubToken.av_len = sprintf(pubToken.av_val, + size_t val_size = 32 + B64INT_LEN + B64DIGEST_LEN + opaque.av_len; + pubToken.av_val = malloc(val_size); + pubToken.av_len = snprintf(pubToken.av_val, val_size, "&challenge=%s&response=%s&opaque=%s", challenge2, response, @@ -2845,8 +2847,9 @@ } else if(r->Link.pubUser.av_len && r->Link.pubPasswd.av_len) { - pubToken.av_val = malloc(r->Link.pubUser.av_len + av_authmod_llnw.av_len + 8); - pubToken.av_len = sprintf(pubToken.av_val, "?%s&user=%s", + size_t val_size = r->Link.pubUser.av_len + av_authmod_llnw.av_len + 8; + pubToken.av_val = malloc(val_size); + pubToken.av_len = snprintf(pubToken.av_val, val_size, "?%s&user=%s", av_authmod_llnw.av_val, r->Link.pubUser.av_val); RTMP_Log(RTMP_LOGDEBUG, "%s, pubToken1: %s", __FUNCTION__, pubToken.av_val); @@ -2923,8 +2926,8 @@ /* FIXME: handle case where user==NULL or nonce==NULL */ - sprintf(nchex, "%08x", nc); - sprintf(cnonce, "%08x", rand()); + snprintf(nchex, sizeof(nchex), "%08x", nc); + snprintf(cnonce, sizeof(cnonce), "%08x", rand()); /* hash1 = hexenc(md5(user + ":" + realm + ":" + password)) */ MD5_Init(&md5ctx); @@ -2937,7 +2940,7 @@ RTMP_Log(RTMP_LOGDEBUG, "%s, md5(%s:%s:%s) =>", __FUNCTION__, user.av_val, realm, r->Link.pubPasswd.av_val); RTMP_LogHexString(RTMP_LOGDEBUG, md5sum_val, MD5_DIGEST_LENGTH); - hexenc(md5sum_val, MD5_DIGEST_LENGTH, hash1); + hexenc(md5sum_val, MD5_DIGEST_LENGTH, hash1, sizeof(hash1)); /* hash2 = hexenc(md5(method + ":/" + app + "/" + appInstance)) */ /* Extract appname + appinstance without query parameters */ @@ -2956,7 +2959,7 @@ RTMP_Log(RTMP_LOGDEBUG, "%s, md5(%s:/%.*s) =>", __FUNCTION__, method, apptmp.av_len, apptmp.av_val); RTMP_LogHexString(RTMP_LOGDEBUG, md5sum_val, MD5_DIGEST_LENGTH); - hexenc(md5sum_val, MD5_DIGEST_LENGTH, hash2); + hexenc(md5sum_val, MD5_DIGEST_LENGTH, hash2, sizeof(hash2)); /* hash3 = hexenc(md5(hash1 + ":" + nonce + ":" + nchex + ":" + cnonce + ":" + qop + ":" + hash2)) */ MD5_Init(&md5ctx); @@ -2975,13 +2978,14 @@ RTMP_Log(RTMP_LOGDEBUG, "%s, md5(%s:%s:%s:%s:%s:%s) =>", __FUNCTION__, hash1, nonce.av_val, nchex, cnonce, qop, hash2); RTMP_LogHexString(RTMP_LOGDEBUG, md5sum_val, MD5_DIGEST_LENGTH); - hexenc(md5sum_val, MD5_DIGEST_LENGTH, hash3); + hexenc(md5sum_val, MD5_DIGEST_LENGTH, hash3, sizeof(hash3)); /* pubToken = &authmod=<authmod>&user=<username>&nonce=<nonce>&cnonce=<cnonce>&nc=<nchex>&response=<hash3> */ /* Append nonces and response to query string which already contains * user + authmod */ - pubToken.av_val = malloc(64 + sizeof(authmod)-1 + user.av_len + nonce.av_len + sizeof(cnonce)-1 + sizeof(nchex)-1 + HEXHASH_LEN); - sprintf(pubToken.av_val, + size_t token_size = 64 + sizeof(authmod)-1 + user.av_len + nonce.av_len + sizeof(cnonce)-1 + sizeof(nchex)-1 + HEXHASH_LEN; + pubToken.av_val = malloc(token_size); + snprintf(pubToken.av_val, token_size, "&nonce=%s&cnonce=%s&nc=%s&response=%s", nonce.av_val, cnonce, nchex, hash3); pubToken.av_len = (int)strlen(pubToken.av_val); @@ -3487,23 +3491,23 @@ DumpMetaData(&prop->p_vu.p_object); break; case AMF_NUMBER: - snprintf(str, 255, "%.2f", prop->p_vu.p_number); + snprintf(str, sizeof(str), "%.2f", prop->p_vu.p_number); break; case AMF_BOOLEAN: - snprintf(str, 255, "%s", + snprintf(str, sizeof(str), "%s", prop->p_vu.p_number != 0. ? "TRUE" : "FALSE"); break; case AMF_STRING: - len = snprintf(str, 255, "%.*s", prop->p_vu.p_aval.av_len, + len = snprintf(str, sizeof(str), "%.*s", prop->p_vu.p_aval.av_len, prop->p_vu.p_aval.av_val); if (len >= 1 && strlen-1 == '\n') strlen-1 = '\0'; break; case AMF_DATE: - snprintf(str, 255, "timestamp:%.2f", prop->p_vu.p_number); + snprintf(str, sizeof(str), "timestamp:%.2f", prop->p_vu.p_number); break; default: - snprintf(str, 255, "INVALID TYPE 0x%02x", + snprintf(str, sizeof(str), "INVALID TYPE 0x%02x", (unsigned char)prop->p_type); } if (str0 && prop->p_name.av_len)
View file
obs-studio-28.1.2.tar.xz/plugins/obs-outputs/rtmp-stream.c -> obs-studio-29.0.0.tar.xz/plugins/obs-outputs/rtmp-stream.c
Changed
@@ -33,7 +33,7 @@ #endif /* dynamic bitrate coefficients */ -#define DBR_INC_TIMER (30ULL * SEC_TO_NSEC) +#define DBR_INC_TIMER (4ULL * SEC_TO_NSEC) #define DBR_TRIGGER_USEC (200ULL * MSEC_TO_USEC) #define MIN_ESTIMATE_DURATION_MS 1000 #define MAX_ESTIMATE_DURATION_MS 2000
View file
obs-studio-28.1.2.tar.xz/plugins/obs-qsv11/CMakeLists.txt -> obs-studio-29.0.0.tar.xz/plugins/obs-qsv11/CMakeLists.txt
Changed
@@ -94,6 +94,8 @@ target_compile_definitions(obs-qsv11 PRIVATE DX11_D3D) if(OS_WINDOWS) + add_subdirectory(obs-qsv-test) + set(MODULE_DESCRIPTION "OBS QSV encoder") configure_file(${CMAKE_SOURCE_DIR}/cmake/bundle/windows/obs-module.rc.in obs-qsv11.rc) @@ -105,7 +107,7 @@ _CRT_NONSTDC_NO_WARNINGS) endif() -set_target_properties(obs-qsv11 PROPERTIES FOLDER "plugins") +set_target_properties(obs-qsv11 PROPERTIES FOLDER "plugins/obs-qsv11") file(GLOB _OBS_QSV11_SOURCE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/*.c ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp)
View file
obs-studio-28.1.2.tar.xz/plugins/obs-qsv11/QSV_Encoder.cpp -> obs-studio-29.0.0.tar.xz/plugins/obs-qsv11/QSV_Encoder.cpp
Changed
@@ -74,117 +74,44 @@ mfxVersion ver = {{0, 1}}; // for backward compatibility std::atomic<bool> is_active{false}; -bool prefer_current_or_igpu_enc(int *iGPUIndex) +void qsv_encoder_version(unsigned short *major, unsigned short *minor) { - IDXGIAdapter *pAdapter; - bool hasIGPU = false; - bool hasDGPU = false; - bool hasCurrent = false; - - HMODULE hDXGI = LoadLibrary(L"dxgi.dll"); - if (hDXGI == NULL) { - return false; - } - - typedef HRESULT(WINAPI * LPCREATEDXGIFACTORY)(REFIID riid, - void **ppFactory); - - LPCREATEDXGIFACTORY pCreateDXGIFactory = - (LPCREATEDXGIFACTORY)GetProcAddress(hDXGI, - "CreateDXGIFactory1"); - if (pCreateDXGIFactory == NULL) { - pCreateDXGIFactory = (LPCREATEDXGIFACTORY)GetProcAddress( - hDXGI, "CreateDXGIFactory"); + *major = ver.Major; + *minor = ver.Minor; +} - if (pCreateDXGIFactory == NULL) { - FreeLibrary(hDXGI); - return false; - } - } +qsv_t *qsv_encoder_open(qsv_param_t *pParams, enum qsv_codec codec) +{ + mfxIMPL impl_list4 = {MFX_IMPL_HARDWARE, MFX_IMPL_HARDWARE2, + MFX_IMPL_HARDWARE3, MFX_IMPL_HARDWARE4}; - IDXGIFactory *pFactory = NULL; - if (FAILED((*pCreateDXGIFactory)(__uuidof(IDXGIFactory), - (void **)(&pFactory)))) { - FreeLibrary(hDXGI); - return false; - } + obs_video_info ovi; + obs_get_video_info(&ovi); + size_t adapter_idx = ovi.adapter; - LUID luid; - bool hasLuid = false; - obs_enter_graphics(); - { - ID3D11Device *pDevice = (ID3D11Device *)gs_get_device_obj(); - Microsoft::WRL::ComPtr<IDXGIDevice> dxgiDevice; - if (SUCCEEDED(pDevice->QueryInterface<IDXGIDevice>( - dxgiDevice.GetAddressOf()))) { - Microsoft::WRL::ComPtr<IDXGIAdapter> dxgiAdapter; - if (SUCCEEDED(dxgiDevice->GetAdapter( - dxgiAdapter.GetAddressOf()))) { - DXGI_ADAPTER_DESC desc; - hasLuid = - SUCCEEDED(dxgiAdapter->GetDesc(&desc)); - if (hasLuid) { - luid = desc.AdapterLuid; - } + // Select current adapter - will be iGPU if exists due to adapter reordering + if (codec == QSV_CODEC_AV1 && !adaptersadapter_idx.supports_av1) { + for (size_t i = 0; i < 4; i++) { + if (adaptersi.supports_av1) { + adapter_idx = i; + break; } } - } - obs_leave_graphics(); - - // Check for i+I cases (Intel discrete + Intel integrated graphics on the same system). Default will be integrated. - for (int adapterIndex = 0; - SUCCEEDED(pFactory->EnumAdapters(adapterIndex, &pAdapter)); - ++adapterIndex) { - DXGI_ADAPTER_DESC AdapterDesc = {}; - const HRESULT hr = pAdapter->GetDesc(&AdapterDesc); - pAdapter->Release(); - - if (SUCCEEDED(hr) && (AdapterDesc.VendorId == 0x8086)) { - if (hasLuid && - (AdapterDesc.AdapterLuid.LowPart == luid.LowPart) && - (AdapterDesc.AdapterLuid.HighPart == - luid.HighPart)) { - hasCurrent = true; - *iGPUIndex = adapterIndex; + } else if (!adaptersadapter_idx.is_intel) { + for (size_t i = 0; i < 4; i++) { + if (adaptersi.is_intel) { + adapter_idx = i; break; } - - if (AdapterDesc.DedicatedVideoMemory <= - 512 * 1024 * 1024) { - hasIGPU = true; - if (iGPUIndex != NULL) { - *iGPUIndex = adapterIndex; - } - } else { - hasDGPU = true; - } } } - pFactory->Release(); - FreeLibrary(hDXGI); - - return hasCurrent || (hasIGPU && hasDGPU); -} - -void qsv_encoder_version(unsigned short *major, unsigned short *minor) -{ - *major = ver.Major; - *minor = ver.Minor; -} - -qsv_t *qsv_encoder_open(qsv_param_t *pParams) -{ - mfxIMPL impl_list4 = {MFX_IMPL_HARDWARE, MFX_IMPL_HARDWARE2, - MFX_IMPL_HARDWARE3, MFX_IMPL_HARDWARE4}; - int igpu_index = -1; - if (prefer_current_or_igpu_enc(&igpu_index) && - (igpu_index < _countof(impl_list))) { - impl = impl_listigpu_index; - } + bool isDGPU = adaptersadapter_idx.is_dgpu; + impl = impl_listadapter_idx; - QSV_Encoder_Internal *pEncoder = new QSV_Encoder_Internal(impl, ver); - mfxStatus sts = pEncoder->Open(pParams); + QSV_Encoder_Internal *pEncoder = + new QSV_Encoder_Internal(impl, ver, isDGPU); + mfxStatus sts = pEncoder->Open(pParams, codec); if (sts != MFX_ERR_NONE) { #define WARN_ERR_IMPL(err, str, err_name) \ @@ -272,6 +199,12 @@ return (qsv_t *)pEncoder; } +bool qsv_encoder_is_dgpu(qsv_t *pContext) +{ + QSV_Encoder_Internal *pEncoder = (QSV_Encoder_Internal *)pContext; + return pEncoder->IsDGPU(); +} + int qsv_encoder_headers(qsv_t *pContext, uint8_t **pSPS, uint8_t **pPPS, uint16_t *pnSPS, uint16_t *pnPPS) { @@ -349,12 +282,12 @@ int qsv_encoder_reconfig(qsv_t *pContext, qsv_param_t *pParams) { QSV_Encoder_Internal *pEncoder = (QSV_Encoder_Internal *)pContext; - mfxStatus sts = pEncoder->Reset(pParams); + pEncoder->UpdateParams(pParams); + mfxStatus sts = pEncoder->ReconfigureEncoder(); - if (sts == MFX_ERR_NONE) - return 0; - else - return -1; + if (sts != MFX_ERR_NONE) + return false; + return true; } enum qsv_cpu_platform qsv_get_cpu_platform() @@ -438,3 +371,13 @@ //assume newer revisions are at least as capable as Haswell return QSV_CPU_PLATFORM_INTEL; } + +int qsv_hevc_encoder_headers(qsv_t *pContext, uint8_t **pVPS, uint8_t **pSPS, + uint8_t **pPPS, uint16_t *pnVPS, uint16_t *pnSPS, + uint16_t *pnPPS) +{ + QSV_Encoder_Internal *pEncoder = (QSV_Encoder_Internal *)pContext; + pEncoder->GetVpsSpsPps(pVPS, pSPS, pPPS, pnVPS, pnSPS, pnPPS); + + return 0; +}
View file
obs-studio-28.1.2.tar.xz/plugins/obs-qsv11/QSV_Encoder.h -> obs-studio-29.0.0.tar.xz/plugins/obs-qsv11/QSV_Encoder.h
Changed
@@ -58,6 +58,7 @@ #include <Windows.h> #include "mfxstructures.h" +#include "mfxadapter.h" #include <stdint.h> #ifdef __cplusplus @@ -73,7 +74,13 @@ {"CBR", false}, {"VBR", false}, {"VCM", true}, {"CQP", false}, {"AVBR", false}, {"ICQ", true}, {"LA_ICQ", true}, {"LA_CBR", true}, {"LA_VBR", true}, {0, false}}; + +static const struct qsv_rate_control_info qsv_av1_ratecontrols = + {{"CBR", false}, {"VBR", false}, {"CQP", false}, {0, false}}; + static const char *const qsv_profile_names = {"high", "main", "baseline", 0}; +static const char *const qsv_profile_names_av1 = {"main", 0}; +static const char *const qsv_profile_names_hevc = {"main", "main10", 0}; static const char *const qsv_usage_names = {"quality", "balanced", "speed", "veryslow", "slower", "slow", "medium", "fast", "faster", @@ -82,6 +89,23 @@ 0}; typedef struct qsv_t qsv_t; +struct adapter_info { + bool is_intel; + bool is_dgpu; + bool supports_av1; + bool supports_hevc; +}; + +enum qsv_codec { + QSV_CODEC_AVC, + QSV_CODEC_AV1, + QSV_CODEC_HEVC, +}; + +#define MAX_ADAPTERS 10 +extern struct adapter_info adaptersMAX_ADAPTERS; +extern size_t adapter_count; + typedef struct { mfxU16 nTargetUsage; /* 1 through 7, 1 being best quality and 7 being the best speed */ @@ -103,8 +127,24 @@ mfxU16 nKeyIntSec; mfxU16 nbFrames; mfxU16 nICQQuality; + mfxU16 VideoFormat; + mfxU16 VideoFullRange; + mfxU16 ColourPrimaries; + mfxU16 TransferCharacteristics; + mfxU16 MatrixCoefficients; + mfxU16 ChromaSampleLocTypeTopField; + mfxU16 ChromaSampleLocTypeBottomField; + mfxU16 DisplayPrimariesX3; + mfxU16 DisplayPrimariesY3; + mfxU16 WhitePointX; + mfxU16 WhitePointY; + mfxU32 MaxDisplayMasteringLuminance; + mfxU32 MinDisplayMasteringLuminance; + mfxU16 MaxContentLightLevel; + mfxU16 MaxPicAverageLightLevel; bool bMBBRC; bool bCQM; + bool video_fmt_10bit; } qsv_param_t; enum qsv_cpu_platform { @@ -132,7 +172,8 @@ const char *tune); int qsv_encoder_reconfig(qsv_t *, qsv_param_t *); void qsv_encoder_version(unsigned short *major, unsigned short *minor); -qsv_t *qsv_encoder_open(qsv_param_t *); +qsv_t *qsv_encoder_open(qsv_param_t *, enum qsv_codec codec); +bool qsv_encoder_is_dgpu(qsv_t *); int qsv_encoder_encode(qsv_t *, uint64_t, uint8_t *, uint8_t *, uint32_t, uint32_t, mfxBitstream **pBS); int qsv_encoder_encode_tex(qsv_t *, uint64_t, uint32_t, uint64_t, uint64_t *, @@ -142,6 +183,10 @@ enum qsv_cpu_platform qsv_get_cpu_platform(); bool prefer_igpu_enc(int *iGPUIndex); +int qsv_hevc_encoder_headers(qsv_t *pContext, uint8_t **vVPS, uint8_t **pSPS, + uint8_t **pPPS, uint16_t *pnVPS, uint16_t *pnSPS, + uint16_t *pnPPS); + #ifdef __cplusplus } #endif
View file
obs-studio-28.1.2.tar.xz/plugins/obs-qsv11/QSV_Encoder_Internal.cpp -> obs-studio-29.0.0.tar.xz/plugins/obs-qsv11/QSV_Encoder_Internal.cpp
Changed
@@ -71,7 +71,8 @@ mfxHDL QSV_Encoder_Internal::g_DX_Handle = NULL; mfxU16 QSV_Encoder_Internal::g_numEncodersOpen = 0; -QSV_Encoder_Internal::QSV_Encoder_Internal(mfxIMPL &impl, mfxVersion &version) +QSV_Encoder_Internal::QSV_Encoder_Internal(mfxIMPL &impl, mfxVersion &version, + bool isDGPU) : m_pmfxSurfaces(NULL), m_pmfxENC(NULL), m_nSPSBufferSize(1024), @@ -80,7 +81,8 @@ m_pTaskPool(NULL), m_nTaskIdx(0), m_nFirstSyncTask(0), - m_outBitstream() + m_outBitstream(), + m_isDGPU(isDGPU) { mfxIMPL tempImpl; mfxStatus sts; @@ -148,7 +150,7 @@ ClearData(); } -mfxStatus QSV_Encoder_Internal::Open(qsv_param_t *pParams) +mfxStatus QSV_Encoder_Internal::Open(qsv_param_t *pParams, enum qsv_codec codec) { mfxStatus sts = MFX_ERR_NONE; @@ -167,7 +169,8 @@ m_pmfxENC = new MFXVideoENCODE(m_session); - InitParams(pParams); + sts = InitParams(pParams, codec); + MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts); sts = m_pmfxENC->Query(&m_mfxEncParams, &m_mfxEncParams); MSDK_IGNORE_MFX_STS(sts, MFX_WRN_INCOMPATIBLE_VIDEO_PARAM); @@ -179,7 +182,7 @@ sts = m_pmfxENC->Init(&m_mfxEncParams); MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts); - sts = GetVideoParam(); + sts = GetVideoParam(codec); MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts); sts = InitBitstream(); @@ -191,28 +194,53 @@ return sts; } -bool QSV_Encoder_Internal::InitParams(qsv_param_t *pParams) +mfxStatus QSV_Encoder_Internal::InitParams(qsv_param_t *pParams, + enum qsv_codec codec) { memset(&m_mfxEncParams, 0, sizeof(m_mfxEncParams)); - m_mfxEncParams.mfx.CodecId = MFX_CODEC_AVC; + if (codec == QSV_CODEC_AVC) + m_mfxEncParams.mfx.CodecId = MFX_CODEC_AVC; + else if (codec == QSV_CODEC_AV1) + m_mfxEncParams.mfx.CodecId = MFX_CODEC_AV1; + else if (codec == QSV_CODEC_HEVC) + m_mfxEncParams.mfx.CodecId = MFX_CODEC_HEVC; + m_mfxEncParams.mfx.GopOptFlag = MFX_GOP_STRICT; - m_mfxEncParams.mfx.NumSlice = 1; + if (codec == QSV_CODEC_HEVC) { + m_mfxEncParams.mfx.NumSlice = 0; + m_mfxEncParams.mfx.IdrInterval = 1; + } else { + m_mfxEncParams.mfx.NumSlice = 1; + } m_mfxEncParams.mfx.TargetUsage = pParams->nTargetUsage; m_mfxEncParams.mfx.CodecProfile = pParams->nCodecProfile; m_mfxEncParams.mfx.FrameInfo.FrameRateExtN = pParams->nFpsNum; m_mfxEncParams.mfx.FrameInfo.FrameRateExtD = pParams->nFpsDen; - m_mfxEncParams.mfx.FrameInfo.FourCC = MFX_FOURCC_NV12; + if (pParams->video_fmt_10bit) { + m_mfxEncParams.mfx.FrameInfo.FourCC = MFX_FOURCC_P010; + m_mfxEncParams.mfx.FrameInfo.BitDepthChroma = 10; + m_mfxEncParams.mfx.FrameInfo.BitDepthLuma = 10; + m_mfxEncParams.mfx.FrameInfo.Shift = 1; + } else { + m_mfxEncParams.mfx.FrameInfo.FourCC = MFX_FOURCC_NV12; + } m_mfxEncParams.mfx.FrameInfo.ChromaFormat = MFX_CHROMAFORMAT_YUV420; m_mfxEncParams.mfx.FrameInfo.PicStruct = MFX_PICSTRUCT_PROGRESSIVE; m_mfxEncParams.mfx.FrameInfo.CropX = 0; m_mfxEncParams.mfx.FrameInfo.CropY = 0; m_mfxEncParams.mfx.FrameInfo.CropW = pParams->nWidth; m_mfxEncParams.mfx.FrameInfo.CropH = pParams->nHeight; - m_mfxEncParams.mfx.GopRefDist = pParams->nbFrames + 1; + if (codec == QSV_CODEC_AV1) + m_mfxEncParams.mfx.GopRefDist = 1; + else + m_mfxEncParams.mfx.GopRefDist = pParams->nbFrames + 1; + + if (codec == QSV_CODEC_HEVC) + m_mfxEncParams.mfx.LowPower = MFX_CODINGOPTION_OFF; enum qsv_cpu_platform qsv_platform = qsv_get_cpu_platform(); - if ((qsv_platform >= QSV_CPU_PLATFORM_ICL || + if ((m_isDGPU || qsv_platform >= QSV_CPU_PLATFORM_ICL || qsv_platform == QSV_CPU_PLATFORM_UNKNOWN) && (pParams->nbFrames == 0) && (m_ver.Major == 1 && m_ver.Minor >= 31)) { @@ -228,11 +256,17 @@ switch (pParams->nRateControl) { case MFX_RATECONTROL_CBR: m_mfxEncParams.mfx.TargetKbps = pParams->nTargetBitRate; + m_mfxEncParams.mfx.BufferSizeInKB = pParams->nTargetBitRate * 2; + m_mfxEncParams.mfx.InitialDelayInKB = + pParams->nTargetBitRate * 1; break; case MFX_RATECONTROL_VBR: case MFX_RATECONTROL_VCM: m_mfxEncParams.mfx.TargetKbps = pParams->nTargetBitRate; m_mfxEncParams.mfx.MaxKbps = pParams->nMaxBitRate; + m_mfxEncParams.mfx.BufferSizeInKB = pParams->nTargetBitRate * 2; + m_mfxEncParams.mfx.InitialDelayInKB = + pParams->nTargetBitRate * 1; break; case MFX_RATECONTROL_CQP: m_mfxEncParams.mfx.QPI = pParams->nQPI; @@ -266,13 +300,12 @@ (mfxU16)(pParams->nKeyIntSec * pParams->nFpsNum / (float)pParams->nFpsDen); - static mfxExtBuffer *extendedBuffers3; - int iBuffers = 0; - if (m_ver.Major == 1 && m_ver.Minor >= 8) { memset(&m_co2, 0, sizeof(mfxExtCodingOption2)); m_co2.Header.BufferId = MFX_EXTBUFF_CODING_OPTION2; m_co2.Header.BufferSz = sizeof(m_co2); + if (codec != QSV_CODEC_AVC) + m_co2.RepeatPPS = MFX_CODINGOPTION_ON; if (pParams->nRateControl == MFX_RATECONTROL_LA_ICQ || pParams->nRateControl == MFX_RATECONTROL_LA) m_co2.LookAheadDepth = pParams->nLADEPTH; @@ -281,34 +314,109 @@ if (pParams->nbFrames > 1) m_co2.BRefType = MFX_B_REF_PYRAMID; if (m_mfxEncParams.mfx.LowPower == MFX_CODINGOPTION_ON) { - m_co2.RepeatPPS = MFX_CODINGOPTION_OFF; + if (codec == QSV_CODEC_AVC) + m_co2.RepeatPPS = MFX_CODINGOPTION_OFF; if (pParams->nRateControl == MFX_RATECONTROL_CBR || pParams->nRateControl == MFX_RATECONTROL_VBR) { m_co2.LookAheadDepth = pParams->nLADEPTH; } } - extendedBuffersiBuffers++ = (mfxExtBuffer *)&m_co2; + extendedBuffers.push_back((mfxExtBuffer *)&m_co2); } - if (m_mfxEncParams.mfx.LowPower == MFX_CODINGOPTION_ON) { + if ((m_mfxEncParams.mfx.LowPower == MFX_CODINGOPTION_ON) || + (pParams->bCQM && m_ver.Major == 1 && m_ver.Minor >= 16)) { memset(&m_co3, 0, sizeof(mfxExtCodingOption3)); m_co3.Header.BufferId = MFX_EXTBUFF_CODING_OPTION3; m_co3.Header.BufferSz = sizeof(m_co3); m_co3.ScenarioInfo = MFX_SCENARIO_GAME_STREAMING; - extendedBuffersiBuffers++ = (mfxExtBuffer *)&m_co3; - } else if (pParams->bCQM) { - if (m_ver.Major == 1 && m_ver.Minor >= 16) { - memset(&m_co3, 0, sizeof(mfxExtCodingOption3)); - m_co3.Header.BufferId = MFX_EXTBUFF_CODING_OPTION3; - m_co3.Header.BufferSz = sizeof(m_co3); - m_co3.ScenarioInfo = 7; // MFX_SCENARIO_GAME_STREAMING - extendedBuffersiBuffers++ = (mfxExtBuffer *)&m_co3; + extendedBuffers.push_back((mfxExtBuffer *)&m_co3); + } + + if (codec == QSV_CODEC_HEVC) { + if ((pParams->nWidth & 15) || (pParams->nHeight & 15)) { + memset(&m_ExtHEVCParam, 0, sizeof(m_ExtHEVCParam)); + m_ExtHEVCParam.Header.BufferId = MFX_EXTBUFF_HEVC_PARAM; + m_ExtHEVCParam.Header.BufferSz = sizeof(m_ExtHEVCParam); + m_ExtHEVCParam.PicWidthInLumaSamples = pParams->nWidth; + m_ExtHEVCParam.PicHeightInLumaSamples = + pParams->nHeight; + extendedBuffers.push_back( + (mfxExtBuffer *)&m_ExtHEVCParam); } } - if (iBuffers > 0) { - m_mfxEncParams.ExtParam = extendedBuffers; - m_mfxEncParams.NumExtParam = (mfxU16)iBuffers; + memset(&m_ExtVideoSignalInfo, 0, sizeof(m_ExtVideoSignalInfo)); + m_ExtVideoSignalInfo.Header.BufferId = MFX_EXTBUFF_VIDEO_SIGNAL_INFO; + m_ExtVideoSignalInfo.Header.BufferSz = sizeof(m_ExtVideoSignalInfo); + m_ExtVideoSignalInfo.VideoFormat = pParams->VideoFormat; + m_ExtVideoSignalInfo.VideoFullRange = pParams->VideoFullRange; + m_ExtVideoSignalInfo.ColourDescriptionPresent = 1; + m_ExtVideoSignalInfo.ColourPrimaries = pParams->ColourPrimaries; + m_ExtVideoSignalInfo.TransferCharacteristics = + pParams->TransferCharacteristics; + m_ExtVideoSignalInfo.MatrixCoefficients = pParams->MatrixCoefficients; + extendedBuffers.push_back((mfxExtBuffer *)&m_ExtVideoSignalInfo); + +/* TODO: Ask Intel why this is MFX_ERR_UNSUPPORTED */ +#if 0 + memset(&m_ExtChromaLocInfo, 0, sizeof(m_ExtChromaLocInfo)); + m_ExtChromaLocInfo.Header.BufferId = MFX_EXTBUFF_CHROMA_LOC_INFO; + m_ExtChromaLocInfo.Header.BufferSz = sizeof(m_ExtChromaLocInfo); + m_ExtChromaLocInfo.ChromaLocInfoPresentFlag = 1; + m_ExtChromaLocInfo.ChromaSampleLocTypeTopField = + pParams->ChromaSampleLocTypeTopField; + m_ExtChromaLocInfo.ChromaSampleLocTypeBottomField = + pParams->ChromaSampleLocTypeBottomField; + extendedBuffers.push_back((mfxExtBuffer *)&m_ExtChromaLocInfo); +#endif + + if (codec != QSV_CODEC_AV1 && pParams->MaxContentLightLevel > 0) { + memset(&m_ExtMasteringDisplayColourVolume, 0, + sizeof(m_ExtMasteringDisplayColourVolume)); + m_ExtMasteringDisplayColourVolume.Header.BufferId = + MFX_EXTBUFF_MASTERING_DISPLAY_COLOUR_VOLUME; + m_ExtMasteringDisplayColourVolume.Header.BufferSz = + sizeof(m_ExtMasteringDisplayColourVolume); + m_ExtMasteringDisplayColourVolume.InsertPayloadToggle = + MFX_PAYLOAD_IDR; + m_ExtMasteringDisplayColourVolume.DisplayPrimariesX0 = + pParams->DisplayPrimariesX0; + m_ExtMasteringDisplayColourVolume.DisplayPrimariesX1 = + pParams->DisplayPrimariesX1; + m_ExtMasteringDisplayColourVolume.DisplayPrimariesX2 = + pParams->DisplayPrimariesX2; + m_ExtMasteringDisplayColourVolume.DisplayPrimariesY0 = + pParams->DisplayPrimariesY0; + m_ExtMasteringDisplayColourVolume.DisplayPrimariesY1 = + pParams->DisplayPrimariesY1; + m_ExtMasteringDisplayColourVolume.DisplayPrimariesY2 = + pParams->DisplayPrimariesY2; + m_ExtMasteringDisplayColourVolume.WhitePointX = + pParams->WhitePointX; + m_ExtMasteringDisplayColourVolume.WhitePointY = + pParams->WhitePointY; + m_ExtMasteringDisplayColourVolume.MaxDisplayMasteringLuminance = + pParams->MaxDisplayMasteringLuminance; + m_ExtMasteringDisplayColourVolume.MinDisplayMasteringLuminance = + pParams->MinDisplayMasteringLuminance; + extendedBuffers.push_back( + (mfxExtBuffer *)&m_ExtMasteringDisplayColourVolume); + + memset(&m_ExtContentLightLevelInfo, 0, + sizeof(m_ExtContentLightLevelInfo)); + m_ExtContentLightLevelInfo.Header.BufferId = + MFX_EXTBUFF_CONTENT_LIGHT_LEVEL_INFO; + m_ExtContentLightLevelInfo.Header.BufferSz = + sizeof(m_ExtContentLightLevelInfo); + m_ExtContentLightLevelInfo.InsertPayloadToggle = + MFX_PAYLOAD_IDR; + m_ExtContentLightLevelInfo.MaxContentLightLevel = + pParams->MaxContentLightLevel; + m_ExtContentLightLevelInfo.MaxPicAverageLightLevel = + pParams->MaxPicAverageLightLevel; + extendedBuffers.push_back( + (mfxExtBuffer *)&m_ExtContentLightLevelInfo); } // Width must be a multiple of 16 @@ -322,6 +430,9 @@ else m_mfxEncParams.IOPattern = MFX_IOPATTERN_IN_SYSTEM_MEMORY; + m_mfxEncParams.ExtParam = extendedBuffers.data(); + m_mfxEncParams.NumExtParam = (mfxU16)extendedBuffers.size(); + mfxStatus sts = m_pmfxENC->Query(&m_mfxEncParams, &m_mfxEncParams); if (sts == MFX_ERR_UNSUPPORTED || sts == MFX_ERR_UNDEFINED_BEHAVIOR) { if (m_mfxEncParams.mfx.LowPower == MFX_CODINGOPTION_ON) { @@ -330,9 +441,26 @@ } } + return sts; +} + +bool QSV_Encoder_Internal::UpdateParams(qsv_param_t *pParams) +{ + switch (pParams->nRateControl) { + case MFX_RATECONTROL_CBR: + m_mfxEncParams.mfx.TargetKbps = pParams->nTargetBitRate; + default: + break; + } + return true; } +mfxStatus QSV_Encoder_Internal::ReconfigureEncoder() +{ + return m_pmfxENC->Reset(&m_mfxEncParams); +} + mfxStatus QSV_Encoder_Internal::AllocateSurfaces() { // Query number of required surfaces for encoder @@ -394,7 +522,7 @@ return sts; } -mfxStatus QSV_Encoder_Internal::GetVideoParam() +mfxStatus QSV_Encoder_Internal::GetVideoParam(enum qsv_codec codec) { memset(&m_parameter, 0, sizeof(m_parameter)); mfxExtCodingOptionSPSPPS opt; @@ -402,19 +530,34 @@ opt.Header.BufferId = MFX_EXTBUFF_CODING_OPTION_SPSPPS; opt.Header.BufferSz = sizeof(mfxExtCodingOptionSPSPPS); - static mfxExtBuffer *extendedBuffers1; - extendedBuffers0 = (mfxExtBuffer *)&opt; - m_parameter.ExtParam = extendedBuffers; - m_parameter.NumExtParam = 1; + std::vector<mfxExtBuffer *> extendedBuffers; + extendedBuffers.reserve(2); opt.SPSBuffer = m_SPSBuffer; opt.PPSBuffer = m_PPSBuffer; opt.SPSBufSize = 1024; // m_nSPSBufferSize; opt.PPSBufSize = 1024; // m_nPPSBufferSize; + mfxExtCodingOptionVPS opt_vps{}; + if (codec == QSV_CODEC_HEVC) { + opt_vps.Header.BufferId = MFX_EXTBUFF_CODING_OPTION_VPS; + opt_vps.Header.BufferSz = sizeof(mfxExtCodingOptionVPS); + opt_vps.VPSBuffer = m_VPSBuffer; + opt_vps.VPSBufSize = 1024; + + extendedBuffers.push_back((mfxExtBuffer *)&opt_vps); + } + + extendedBuffers.push_back((mfxExtBuffer *)&opt); + + m_parameter.ExtParam = extendedBuffers.data(); + m_parameter.NumExtParam = (mfxU16)extendedBuffers.size(); + mfxStatus sts = m_pmfxENC->GetVideoParam(&m_parameter); MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts); + if (codec == QSV_CODEC_HEVC) + m_nVPSBufferSize = opt_vps.VPSBufSize; m_nSPSBufferSize = opt.SPSBufSize; m_nPPSBufferSize = opt.PPSBufSize; @@ -430,6 +573,20 @@ *pnPPSBuf = m_nPPSBufferSize; } +void QSV_Encoder_Internal::GetVpsSpsPps(mfxU8 **pVPSBuf, mfxU8 **pSPSBuf, + mfxU8 **pPPSBuf, mfxU16 *pnVPSBuf, + mfxU16 *pnSPSBuf, mfxU16 *pnPPSBuf) +{ + *pVPSBuf = m_VPSBuffer; + *pnVPSBuf = m_nVPSBufferSize; + + *pSPSBuf = m_SPSBuffer; + *pnSPSBuf = m_nSPSBufferSize; + + *pPPSBuf = m_PPSBuffer; + *pnPPSBuf = m_nPPSBufferSize; +} + mfxStatus QSV_Encoder_Internal::InitBitstream() { m_nTaskPool = m_parameter.AsyncDepth; @@ -461,6 +618,41 @@ return MFX_ERR_NONE; } +mfxStatus QSV_Encoder_Internal::LoadP010(mfxFrameSurface1 *pSurface, + uint8_t *pDataY, uint8_t *pDataUV, + uint32_t strideY, uint32_t strideUV) +{ + mfxU16 w, h, i, pitch; + mfxU8 *ptr; + mfxFrameInfo *pInfo = &pSurface->Info; + mfxFrameData *pData = &pSurface->Data; + + if (pInfo->CropH > 0 && pInfo->CropW > 0) { + w = pInfo->CropW; + h = pInfo->CropH; + } else { + w = pInfo->Width; + h = pInfo->Height; + } + + pitch = pData->Pitch; + ptr = pData->Y + pInfo->CropX + pInfo->CropY * pData->Pitch; + const size_t line_size = w * 2; + + // load Y plane + for (i = 0; i < h; i++) + memcpy(ptr + i * pitch, pDataY + i * strideY, line_size); + + // load UV plane + h /= 2; + ptr = pData->UV + pInfo->CropX + (pInfo->CropY / 2) * pitch; + + for (i = 0; i < h; i++) + memcpy(ptr + i * pitch, pDataUV + i * strideUV, line_size); + + return MFX_ERR_NONE; +} + mfxStatus QSV_Encoder_Internal::LoadNV12(mfxFrameSurface1 *pSurface, uint8_t *pDataY, uint8_t *pDataUV, uint32_t strideY, uint32_t strideUV) @@ -567,7 +759,10 @@ MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts); } - sts = LoadNV12(pSurface, pDataY, pDataUV, strideY, strideUV); + sts = (pSurface->Info.FourCC == MFX_FOURCC_P010) + ? LoadP010(pSurface, pDataY, pDataUV, strideY, strideUV) + : LoadNV12(pSurface, pDataY, pDataUV, strideY, strideUV); + MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts); pSurface->Data.TimeStamp = ts; @@ -729,12 +924,13 @@ return sts; } -mfxStatus QSV_Encoder_Internal::Reset(qsv_param_t *pParams) +mfxStatus QSV_Encoder_Internal::Reset(qsv_param_t *pParams, + enum qsv_codec codec) { mfxStatus sts = ClearData(); MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts); - sts = Open(pParams); + sts = Open(pParams, codec); MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts); return sts;
View file
obs-studio-28.1.2.tar.xz/plugins/obs-qsv11/QSV_Encoder_Internal.h -> obs-studio-29.0.0.tar.xz/plugins/obs-qsv11/QSV_Encoder_Internal.h
Changed
@@ -59,14 +59,18 @@ #include "QSV_Encoder.h" #include "common_utils.h" +#include <vector> + class QSV_Encoder_Internal { public: - QSV_Encoder_Internal(mfxIMPL &impl, mfxVersion &version); + QSV_Encoder_Internal(mfxIMPL &impl, mfxVersion &version, bool isDGPU); ~QSV_Encoder_Internal(); - mfxStatus Open(qsv_param_t *pParams); + mfxStatus Open(qsv_param_t *pParams, enum qsv_codec codec); void GetSPSPPS(mfxU8 **pSPSBuf, mfxU8 **pPPSBuf, mfxU16 *pnSPSBuf, mfxU16 *pnPPSBuf); + void GetVpsSpsPps(mfxU8 **pVPSBuf, mfxU8 **pSPSBuf, mfxU8 **pPPSBuf, + mfxU16 *pnVPSBuf, mfxU16 *pnSPSBuf, mfxU16 *pnPPSBuf); mfxStatus Encode(uint64_t ts, uint8_t *pDataY, uint8_t *pDataUV, uint32_t strideY, uint32_t strideUV, mfxBitstream **pBS); @@ -74,16 +78,23 @@ uint64_t lock_key, uint64_t *next_key, mfxBitstream **pBS); mfxStatus ClearData(); - mfxStatus Reset(qsv_param_t *pParams); + mfxStatus Reset(qsv_param_t *pParams, enum qsv_codec codec); + mfxStatus ReconfigureEncoder(); + bool UpdateParams(qsv_param_t *pParams); + + bool IsDGPU() const { return m_isDGPU; } protected: - bool InitParams(qsv_param_t *pParams); + mfxStatus InitParams(qsv_param_t *pParams, enum qsv_codec codec); mfxStatus AllocateSurfaces(); - mfxStatus GetVideoParam(); + mfxStatus GetVideoParam(enum qsv_codec codec); mfxStatus InitBitstream(); mfxStatus LoadNV12(mfxFrameSurface1 *pSurface, uint8_t *pDataY, uint8_t *pDataUV, uint32_t strideY, uint32_t strideUV); + mfxStatus LoadP010(mfxFrameSurface1 *pSurface, uint8_t *pDataY, + uint8_t *pDataUV, uint32_t strideY, + uint32_t strideUV); mfxStatus Drain(); int GetFreeTaskIndex(Task *pTaskPool, mfxU16 nPoolSize); @@ -97,14 +108,22 @@ mfxFrameSurface1 **m_pmfxSurfaces; mfxU16 m_nSurfNum; MFXVideoENCODE *m_pmfxENC; + mfxU8 m_VPSBuffer1024; mfxU8 m_SPSBuffer1024; mfxU8 m_PPSBuffer1024; + mfxU16 m_nVPSBufferSize; mfxU16 m_nSPSBufferSize; mfxU16 m_nPPSBufferSize; mfxVideoParam m_parameter; + std::vector<mfxExtBuffer *> extendedBuffers; mfxExtCodingOption3 m_co3; mfxExtCodingOption2 m_co2; mfxExtCodingOption m_co; + mfxExtHEVCParam m_ExtHEVCParam{}; + mfxExtVideoSignalInfo m_ExtVideoSignalInfo{}; + mfxExtChromaLocInfo m_ExtChromaLocInfo{}; + mfxExtMasteringDisplayColourVolume m_ExtMasteringDisplayColourVolume{}; + mfxExtContentLightLevelInfo m_ExtContentLightLevelInfo{}; mfxU16 m_nTaskPool; Task *m_pTaskPool; int m_nTaskIdx; @@ -113,6 +132,7 @@ bool m_bIsWindows8OrGreater; bool m_bUseD3D11; bool m_bD3D9HACK; + bool m_isDGPU; static mfxU16 g_numEncodersOpen; static mfxHDL g_DX_Handle; // we only want one handle for all instances to use;
View file
obs-studio-28.1.2.tar.xz/plugins/obs-qsv11/common_directx11.cpp -> obs-studio-29.0.0.tar.xz/plugins/obs-qsv11/common_directx11.cpp
Changed
@@ -169,6 +169,8 @@ request->Info .FourCC) //|| MFX_FOURCC_P8_TEXTURE == request->Info.FourCC format = DXGI_FORMAT_P8; + else if (MFX_FOURCC_P010 == request->Info.FourCC) + format = DXGI_FORMAT_P010; else format = DXGI_FORMAT_UNKNOWN; @@ -389,6 +391,14 @@ ptr->U = 0; ptr->V = 0; break; + case DXGI_FORMAT_P010: + ptr->Pitch = (mfxU16)lockedRect.RowPitch; + ptr->PitchHigh = 0; + ptr->Y = (mfxU8 *)lockedRect.pData; + ptr->U = (mfxU8 *)lockedRect.pData + + desc.Height * lockedRect.RowPitch; + ptr->V = ptr->U + 2; + break; default: return MFX_ERR_LOCK_MEMORY; }
View file
obs-studio-29.0.0.tar.xz/plugins/obs-qsv11/obs-qsv-test
Added
+(directory)
View file
obs-studio-29.0.0.tar.xz/plugins/obs-qsv11/obs-qsv-test/CMakeLists.txt
Added
@@ -0,0 +1,11 @@ +project(obs-qsv-test) + +include_directories(SYSTEM ${CMAKE_SOURCE_DIR}/libobs) + +add_executable(obs-qsv-test) +target_sources(obs-qsv-test PRIVATE obs-qsv-test.cpp) +target_link_libraries(obs-qsv-test d3d11 dxgi dxguid OBS::libmfx) + +set_target_properties(obs-qsv-test PROPERTIES FOLDER "plugins/obs-qsv11") + +setup_binary_target(obs-qsv-test)
View file
obs-studio-29.0.0.tar.xz/plugins/obs-qsv11/obs-qsv-test/obs-qsv-test.cpp
Added
@@ -0,0 +1,160 @@ +#include "mfxstructures.h" +#include "mfxadapter.h" +#include "mfxvideo++.h" +#include "../common_utils.h" + +#include <util/windows/ComPtr.hpp> + +#include <dxgi.h> +#include <d3d11.h> +#include <d3d11_1.h> + +#include <vector> +#include <string> +#include <map> + +#ifdef _MSC_VER +extern "C" __declspec(dllexport) DWORD NvOptimusEnablement = 1; +extern "C" __declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 1; +#endif + +#define INTEL_VENDOR_ID 0x8086 + +struct adapter_caps { + bool is_intel = false; + bool is_dgpu = false; + bool supports_av1 = false; + bool supports_hevc = false; +}; + +static std::vector<uint64_t> luid_order; +static std::map<uint32_t, adapter_caps> adapter_info; + +static bool has_encoder(mfxIMPL impl, mfxU32 codec_id) +{ + MFXVideoSession session; + mfxInitParam init_param = {}; + init_param.Implementation = impl; + init_param.Version.Major = 1; + init_param.Version.Minor = 0; + mfxStatus sts = session.InitEx(init_param); + + mfxVideoParam video_param; + memset(&video_param, 0, sizeof(video_param)); + video_param.mfx.CodecId = codec_id; + video_param.mfx.FrameInfo.FourCC = MFX_FOURCC_NV12; + video_param.mfx.FrameInfo.ChromaFormat = MFX_CHROMAFORMAT_YUV420; + video_param.mfx.FrameInfo.Width = MSDK_ALIGN16(1280); + video_param.mfx.FrameInfo.Height = MSDK_ALIGN16(720); + sts = MFXVideoENCODE_Query(session, &video_param, &video_param); + session.Close(); + + return sts == MFX_ERR_NONE; +} + +static inline uint32_t get_adapter_idx(uint32_t adapter_idx, LUID luid) +{ + for (size_t i = 0; i < luid_order.size(); i++) { + if (luid_orderi == *(uint64_t *)&luid) { + return (uint32_t)i; + } + } + + return adapter_idx; +} + +static bool get_adapter_caps(IDXGIFactory *factory, uint32_t adapter_idx) +{ + mfxIMPL impls4 = {MFX_IMPL_HARDWARE, MFX_IMPL_HARDWARE2, + MFX_IMPL_HARDWARE3, MFX_IMPL_HARDWARE4}; + HRESULT hr; + + ComPtr<IDXGIAdapter> adapter; + hr = factory->EnumAdapters(adapter_idx, &adapter); + if (FAILED(hr)) + return false; + + DXGI_ADAPTER_DESC desc; + adapter->GetDesc(&desc); + + uint32_t luid_idx = get_adapter_idx(adapter_idx, desc.AdapterLuid); + adapter_caps &caps = adapter_infoluid_idx; + if (desc.VendorId != INTEL_VENDOR_ID) + return true; + + bool dgpu = desc.DedicatedVideoMemory > 512 * 1024 * 1024; + mfxIMPL impl = implsadapter_idx; + + caps.is_intel = true; + caps.is_dgpu = dgpu; + caps.supports_av1 = has_encoder(impl, MFX_CODEC_AV1); +#if ENABLE_HEVC + caps.supports_hevc = has_encoder(impl, MFX_CODEC_HEVC); +#endif + + return true; +} + +#define CHECK_TIMEOUT_MS 10000 + +DWORD WINAPI TimeoutThread(LPVOID param) +{ + HANDLE hMainThread = (HANDLE)param; + + DWORD ret = WaitForSingleObject(hMainThread, CHECK_TIMEOUT_MS); + if (ret == WAIT_TIMEOUT) + TerminateProcess(GetCurrentProcess(), STATUS_TIMEOUT); + + CloseHandle(hMainThread); + + return 0; +} + +int main(int argc, char *argv) +try { + ComPtr<IDXGIFactory> factory; + HRESULT hr; + + HANDLE hMainThread; + DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), + GetCurrentProcess(), &hMainThread, 0, FALSE, + DUPLICATE_SAME_ACCESS); + DWORD threadId; + HANDLE hThread; + hThread = + CreateThread(NULL, 0, TimeoutThread, hMainThread, 0, &threadId); + CloseHandle(hThread); + + /* --------------------------------------------------------- */ + /* parse expected LUID order */ + + for (int i = 1; i < argc; i++) { + luid_order.push_back(strtoull(argvi, NULL, 16)); + } + + /* --------------------------------------------------------- */ + /* query qsv support */ + + hr = CreateDXGIFactory1(__uuidof(IDXGIFactory), (void **)&factory); + if (FAILED(hr)) + throw "CreateDXGIFactory1 failed"; + + uint32_t idx = 0; + while (get_adapter_caps(factory, idx++) && idx < 4) + ; + + for (auto &idx, caps : adapter_info) { + printf("%u\n", idx); + printf("is_intel=%s\n", caps.is_intel ? "true" : "false"); + printf("is_dgpu=%s\n", caps.is_dgpu ? "true" : "false"); + printf("supports_av1=%s\n", + caps.supports_av1 ? "true" : "false"); + printf("supports_hevc=%s\n", + caps.supports_hevc ? "true" : "false"); + } + + return 0; +} catch (const char *text) { + printf("error\nstring=%s\n", text); + return 0; +}
View file
obs-studio-28.1.2.tar.xz/plugins/obs-qsv11/obs-qsv11-plugin-main.c -> obs-studio-29.0.0.tar.xz/plugins/obs-qsv11/obs-qsv11-plugin-main.c
Changed
@@ -54,39 +54,136 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include <obs-module.h> -#include "mfxsession.h" +#include <util/windows/device-enum.h> +#include <util/config-file.h> +#include <util/platform.h> +#include <util/pipe.h> +#include <util/dstr.h> +#include "QSV_Encoder.h" OBS_DECLARE_MODULE() OBS_MODULE_USE_DEFAULT_LOCALE("obs-qsv11", "en-US") MODULE_EXPORT const char *obs_module_description(void) { - return "Intel Quick Sync Video H.264 encoder support for Windows"; + return "Intel Quick Sync Video support for Windows"; } extern struct obs_encoder_info obs_qsv_encoder; +extern struct obs_encoder_info obs_qsv_encoder_v2; extern struct obs_encoder_info obs_qsv_encoder_tex; +extern struct obs_encoder_info obs_qsv_encoder_tex_v2; +extern struct obs_encoder_info obs_qsv_av1_encoder_tex; +extern struct obs_encoder_info obs_qsv_av1_encoder; +extern struct obs_encoder_info obs_qsv_hevc_encoder_tex; +extern struct obs_encoder_info obs_qsv_hevc_encoder; + +extern bool av1_supported(mfxIMPL impl); + +struct adapter_info adaptersMAX_ADAPTERS = {0}; +size_t adapter_count = 0; + +static bool enum_luids(void *param, uint32_t idx, uint64_t luid) +{ + struct dstr *cmd = param; + dstr_catf(cmd, " %llX", luid); + UNUSED_PARAMETER(idx); + return true; +} bool obs_module_load(void) { - mfxIMPL impl = MFX_IMPL_HARDWARE_ANY | MFX_IMPL_VIA_D3D11; - mfxVersion ver = {{0, 1}}; - mfxSession session; - mfxStatus sts; + char *test_exe = os_get_executable_path_ptr("obs-qsv-test.exe"); + struct dstr cmd = {0}; + struct dstr caps_str = {0}; + os_process_pipe_t *pp = NULL; + config_t *config = NULL; + + dstr_copy(&cmd, test_exe); + enum_graphics_device_luids(enum_luids, &cmd); + + pp = os_process_pipe_create(cmd.array, "r"); + if (!pp) { + blog(LOG_INFO, "Failed to launch the QSV test process I guess"); + goto fail; + } - sts = MFXInit(impl, &ver, &session); + for (;;) { + char data2048; + size_t len = + os_process_pipe_read(pp, (uint8_t *)data, sizeof(data)); + if (!len) + break; - if (sts == MFX_ERR_NONE) { - obs_register_encoder(&obs_qsv_encoder); + dstr_ncat(&caps_str, data, len); + } + + if (dstr_is_empty(&caps_str)) { + blog(LOG_INFO, "Seems the QSV test subprocess crashed. " + "Better there than here I guess. " + "Let's just skip loading QSV then I suppose."); + goto fail; + } + + if (config_open_string(&config, caps_str.array) != 0) { + blog(LOG_INFO, "Couldn't open QSV configuration string"); + goto fail; + } + + const char *error = config_get_string(config, "error", "string"); + if (error) { + blog(LOG_INFO, "Error querying QSV support: %s", error); + goto fail; + } + + adapter_count = config_num_sections(config); + bool avc_supported = false; + bool av1_supported = false; + bool hevc_supported = false; + + if (adapter_count > MAX_ADAPTERS) + adapter_count = MAX_ADAPTERS; + + for (size_t i = 0; i < adapter_count; i++) { + char section16; + snprintf(section, sizeof(section), "%d", (int)i); + + struct adapter_info *adapter = &adaptersi; + adapter->is_intel = + config_get_bool(config, section, "is_intel"); + adapter->is_dgpu = config_get_bool(config, section, "is_dgpu"); + adapter->supports_av1 = + config_get_bool(config, section, "supports_av1"); + adapter->supports_hevc = + config_get_bool(config, section, "supports_hevc"); + + avc_supported |= adapter->is_intel; + av1_supported |= adapter->supports_av1; + hevc_supported |= adapter->supports_hevc; + } + + if (avc_supported) { + obs_register_encoder(&obs_qsv_encoder_tex_v2); obs_register_encoder(&obs_qsv_encoder_tex); - MFXClose(session); - } else { - impl = MFX_IMPL_HARDWARE_ANY | MFX_IMPL_VIA_D3D9; - sts = MFXInit(impl, &ver, &session); - if (sts == MFX_ERR_NONE) { - obs_register_encoder(&obs_qsv_encoder); - MFXClose(session); - } + obs_register_encoder(&obs_qsv_encoder_v2); + obs_register_encoder(&obs_qsv_encoder); + } + if (av1_supported) { + obs_register_encoder(&obs_qsv_av1_encoder_tex); + obs_register_encoder(&obs_qsv_av1_encoder); + } +#if ENABLE_HEVC + if (hevc_supported) { + obs_register_encoder(&obs_qsv_hevc_encoder_tex); + obs_register_encoder(&obs_qsv_hevc_encoder); } +#endif + +fail: + config_close(config); + dstr_free(&caps_str); + dstr_free(&cmd); + os_process_pipe_destroy(pp); + bfree(test_exe); return true; }
View file
obs-studio-28.1.2.tar.xz/plugins/obs-qsv11/obs-qsv11.c -> obs-studio-29.0.0.tar.xz/plugins/obs-qsv11/obs-qsv11.c
Changed
@@ -59,6 +59,7 @@ #include <util/darray.h> #include <util/platform.h> #include <obs-module.h> +#include <obs-hevc.h> #include <obs-avc.h> #include <d3d11.h> #include <dxgi1_2.h> @@ -84,6 +85,8 @@ struct obs_qsv { obs_encoder_t *encoder; + enum qsv_codec codec; + qsv_param_t params; qsv_t *context; @@ -107,12 +110,30 @@ static int64_t g_prevDts; static bool g_bFirst; +static const char *obs_qsv_getname_v1(void *type_data) +{ + UNUSED_PARAMETER(type_data); + return "QuickSync H.264 (v1 deprecated)"; +} + static const char *obs_qsv_getname(void *type_data) { UNUSED_PARAMETER(type_data); return "QuickSync H.264"; } +static const char *obs_qsv_getname_av1(void *type_data) +{ + UNUSED_PARAMETER(type_data); + return "QuickSync AV1"; +} + +static const char *obs_qsv_getname_hevc(void *type_data) +{ + UNUSED_PARAMETER(type_data); + return "QuickSync HEVC"; +} + static void obs_qsv_stop(void *data); static void clear_data(struct obs_qsv *obsqsv) @@ -143,16 +164,21 @@ } } -static void obs_qsv_defaults(obs_data_t *settings) +static void obs_qsv_defaults(obs_data_t *settings, int ver, + enum qsv_codec codec) { obs_data_set_default_string(settings, "target_usage", "balanced"); obs_data_set_default_int(settings, "bitrate", 2500); obs_data_set_default_int(settings, "max_bitrate", 3000); - obs_data_set_default_string(settings, "profile", "high"); + obs_data_set_default_string(settings, "profile", + codec == QSV_CODEC_AVC ? "high" : "main"); obs_data_set_default_string(settings, "rate_control", "CBR"); + obs_data_set_default_int(settings, "__ver", ver); + obs_data_set_default_int(settings, "accuracy", 1000); obs_data_set_default_int(settings, "convergence", 1); + obs_data_set_default_int(settings, "cqp", 23); obs_data_set_default_int(settings, "qpi", 23); obs_data_set_default_int(settings, "qpp", 23); obs_data_set_default_int(settings, "qpb", 23); @@ -164,6 +190,26 @@ obs_data_set_default_bool(settings, "enhancements", false); } +static void obs_qsv_defaults_h264_v1(obs_data_t *settings) +{ + obs_qsv_defaults(settings, 1, QSV_CODEC_AVC); +} + +static void obs_qsv_defaults_h264_v2(obs_data_t *settings) +{ + obs_qsv_defaults(settings, 2, QSV_CODEC_AVC); +} + +static void obs_qsv_defaults_av1(obs_data_t *settings) +{ + obs_qsv_defaults(settings, 2, QSV_CODEC_AV1); +} + +static void obs_qsv_defaults_hevc(obs_data_t *settings) +{ + obs_qsv_defaults(settings, 2, QSV_CODEC_HEVC); +} + static inline void add_strings(obs_property_t *list, const char *const *strings) { while (*strings) { @@ -287,11 +333,17 @@ bVisible = astrcmpi(rate_control, "CQP") == 0; p = obs_properties_get(ppts, "qpi"); - obs_property_set_visible(p, bVisible); + if (p) + obs_property_set_visible(p, bVisible); p = obs_properties_get(ppts, "qpb"); - obs_property_set_visible(p, bVisible); + if (p) + obs_property_set_visible(p, bVisible); p = obs_properties_get(ppts, "qpp"); - obs_property_set_visible(p, bVisible); + if (p) + obs_property_set_visible(p, bVisible); + p = obs_properties_get(ppts, "cqp"); + if (p) + obs_property_set_visible(p, bVisible); bVisible = astrcmpi(rate_control, "ICQ") == 0 || astrcmpi(rate_control, "LA_ICQ") == 0; @@ -335,13 +387,45 @@ } } -static obs_properties_t *obs_qsv_props(void *unused) +static obs_properties_t *obs_qsv_props(enum qsv_codec codec, void *unused, + int ver) { UNUSED_PARAMETER(unused); obs_properties_t *props = obs_properties_create(); obs_property_t *prop; + prop = obs_properties_add_list(props, "rate_control", TEXT_RATE_CONTROL, + OBS_COMBO_TYPE_LIST, + OBS_COMBO_FORMAT_STRING); + + if (codec == QSV_CODEC_AVC || codec == QSV_CODEC_HEVC) + add_rate_controls(prop, qsv_ratecontrols); + else if (codec == QSV_CODEC_AV1) + add_rate_controls(prop, qsv_av1_ratecontrols); + + obs_property_set_modified_callback(prop, rate_control_modified); + + prop = obs_properties_add_int(props, "bitrate", TEXT_TARGET_BITRATE, 50, + 10000000, 50); + obs_property_int_set_suffix(prop, " Kbps"); + + prop = obs_properties_add_int(props, "max_bitrate", TEXT_MAX_BITRATE, + 50, 10000000, 50); + obs_property_int_set_suffix(prop, " Kbps"); + + if (ver >= 2) { + obs_properties_add_int(props, "cqp", "CQP", 1, + codec == QSV_CODEC_AV1 ? 63 : 51, 1); + } else { + obs_properties_add_int(props, "qpi", "QPI", 1, 51, 1); + obs_properties_add_int(props, "qpp", "QPP", 1, 51, 1); + obs_properties_add_int(props, "qpb", "QPB", 1, 51, 1); + } + + obs_properties_add_int(props, "icq_quality", TEXT_ICQ_QUALITY, 1, 51, + 1); + prop = obs_properties_add_list(props, "target_usage", TEXT_SPEED, OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_STRING); @@ -350,7 +434,13 @@ prop = obs_properties_add_list(props, "profile", TEXT_PROFILE, OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_STRING); - add_strings(prop, qsv_profile_names); + + if (codec == QSV_CODEC_AVC) + add_strings(prop, qsv_profile_names); + else if (codec == QSV_CODEC_AV1) + add_strings(prop, qsv_profile_names_av1); + else if (codec == QSV_CODEC_HEVC) + add_strings(prop, qsv_profile_names_hevc); obs_property_set_modified_callback(prop, profile_modified); @@ -358,28 +448,9 @@ 20, 1); obs_property_int_set_suffix(prop, " s"); - prop = obs_properties_add_list(props, "rate_control", TEXT_RATE_CONTROL, - OBS_COMBO_TYPE_LIST, - OBS_COMBO_FORMAT_STRING); - add_rate_controls(prop, qsv_ratecontrols); - obs_property_set_modified_callback(prop, rate_control_modified); - - prop = obs_properties_add_int(props, "bitrate", TEXT_TARGET_BITRATE, 50, - 10000000, 50); - obs_property_int_set_suffix(prop, " Kbps"); - - prop = obs_properties_add_int(props, "max_bitrate", TEXT_MAX_BITRATE, - 50, 10000000, 50); - obs_property_int_set_suffix(prop, " Kbps"); - obs_properties_add_int(props, "accuracy", TEXT_ACCURACY, 0, 10000, 1); obs_properties_add_int(props, "convergence", TEXT_CONVERGENCE, 0, 10, 1); - obs_properties_add_int(props, "qpi", "QPI", 1, 51, 1); - obs_properties_add_int(props, "qpp", "QPP", 1, 51, 1); - obs_properties_add_int(props, "qpb", "QPB", 1, 51, 1); - obs_properties_add_int(props, "icq_quality", TEXT_ICQ_QUALITY, 1, 51, - 1); prop = obs_properties_add_list(props, "latency", TEXT_LATENCY, OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_STRING); @@ -387,15 +458,39 @@ obs_property_set_long_description(prop, obs_module_text("Latency.ToolTip")); - obs_properties_add_int(props, "bframes", TEXT_BFRAMES, 0, 3, 1); + if (codec != QSV_CODEC_AV1) + obs_properties_add_int(props, "bframes", TEXT_BFRAMES, 0, 3, 1); if (is_skl_or_greater_platform()) obs_properties_add_bool(props, "enhancements", TEXT_PERCEPTUAL_ENHANCEMENTS); - return props; } +static obs_properties_t *obs_qsv_props_h264(void *unused) +{ + UNUSED_PARAMETER(unused); + return obs_qsv_props(QSV_CODEC_AVC, unused, 1); +} + +static obs_properties_t *obs_qsv_props_h264_v2(void *unused) +{ + UNUSED_PARAMETER(unused); + return obs_qsv_props(QSV_CODEC_AVC, unused, 2); +} + +static obs_properties_t *obs_qsv_props_av1(void *unused) +{ + UNUSED_PARAMETER(unused); + return obs_qsv_props(QSV_CODEC_AV1, unused, 2); +} + +static obs_properties_t *obs_qsv_props_hevc(void *unused) +{ + UNUSED_PARAMETER(unused); + return obs_qsv_props(QSV_CODEC_HEVC, unused, 2); +} + static void update_params(struct obs_qsv *obsqsv, obs_data_t *settings) { video_t *video = obs_encoder_video(obsqsv->encoder); @@ -416,6 +511,8 @@ int qpi = (int)obs_data_get_int(settings, "qpi"); int qpp = (int)obs_data_get_int(settings, "qpp"); int qpb = (int)obs_data_get_int(settings, "qpb"); + int cqp = (int)obs_data_get_int(settings, "cqp"); + int ver = (int)obs_data_get_int(settings, "__ver"); int icq_quality = (int)obs_data_get_int(settings, "icq_quality"); int keyint_sec = (int)obs_data_get_int(settings, "keyint_sec"); bool cbr_override = obs_data_get_bool(settings, "cbr"); @@ -426,7 +523,8 @@ bFrames = (int)obs_data_get_int(settings, "bf"); enum qsv_cpu_platform plat = qsv_get_cpu_platform(); - if (plat == QSV_CPU_PLATFORM_IVB || plat == QSV_CPU_PLATFORM_SNB) + if (obsqsv->codec == QSV_CODEC_AV1 || plat == QSV_CPU_PLATFORM_IVB || + plat == QSV_CPU_PLATFORM_SNB) bFrames = 0; int width = (int)obs_encoder_get_width(obsqsv->encoder); @@ -452,12 +550,95 @@ else if (astrcmpi(target_usage, "veryfast") == 0) obsqsv->params.nTargetUsage = MFX_TARGETUSAGE_7; - if (astrcmpi(profile, "baseline") == 0) - obsqsv->params.nCodecProfile = MFX_PROFILE_AVC_BASELINE; - else if (astrcmpi(profile, "main") == 0) - obsqsv->params.nCodecProfile = MFX_PROFILE_AVC_MAIN; - else if (astrcmpi(profile, "high") == 0) - obsqsv->params.nCodecProfile = MFX_PROFILE_AVC_HIGH; + if (obsqsv->codec == QSV_CODEC_AVC) { + if (astrcmpi(profile, "baseline") == 0) + obsqsv->params.nCodecProfile = MFX_PROFILE_AVC_BASELINE; + else if (astrcmpi(profile, "main") == 0) + obsqsv->params.nCodecProfile = MFX_PROFILE_AVC_MAIN; + else if (astrcmpi(profile, "high") == 0) + obsqsv->params.nCodecProfile = MFX_PROFILE_AVC_HIGH; + + } else if (obsqsv->codec == QSV_CODEC_HEVC) { + if (astrcmpi(profile, "main") == 0) { + obsqsv->params.nCodecProfile = MFX_PROFILE_HEVC_MAIN; + if (obs_p010_tex_active()) { + blog(LOG_WARNING, + "qsv encoder Forcing main10 for P010"); + obsqsv->params.nCodecProfile = + MFX_PROFILE_HEVC_MAIN10; + } + + } else if (astrcmpi(profile, "main10") == 0) { + obsqsv->params.nCodecProfile = MFX_PROFILE_HEVC_MAIN10; + } + + } else if (obsqsv->codec == QSV_CODEC_AV1) { + obsqsv->params.nCodecProfile = MFX_PROFILE_AV1_MAIN; + } + + obsqsv->params.VideoFormat = 5; + obsqsv->params.VideoFullRange = voi->range == VIDEO_RANGE_FULL; + + switch (voi->colorspace) { + case VIDEO_CS_601: + obsqsv->params.ColourPrimaries = 6; + obsqsv->params.TransferCharacteristics = 6; + obsqsv->params.MatrixCoefficients = 6; + obsqsv->params.ChromaSampleLocTypeTopField = 0; + obsqsv->params.ChromaSampleLocTypeBottomField = 0; + break; + case VIDEO_CS_DEFAULT: + case VIDEO_CS_709: + obsqsv->params.ColourPrimaries = 1; + obsqsv->params.TransferCharacteristics = 1; + obsqsv->params.MatrixCoefficients = 1; + obsqsv->params.ChromaSampleLocTypeTopField = 0; + obsqsv->params.ChromaSampleLocTypeBottomField = 0; + break; + case VIDEO_CS_SRGB: + obsqsv->params.ColourPrimaries = 1; + obsqsv->params.TransferCharacteristics = 13; + obsqsv->params.MatrixCoefficients = 1; + obsqsv->params.ChromaSampleLocTypeTopField = 0; + obsqsv->params.ChromaSampleLocTypeBottomField = 0; + break; + case VIDEO_CS_2100_PQ: + obsqsv->params.ColourPrimaries = 9; + obsqsv->params.TransferCharacteristics = 16; + obsqsv->params.MatrixCoefficients = 9; + obsqsv->params.ChromaSampleLocTypeTopField = 2; + obsqsv->params.ChromaSampleLocTypeBottomField = 2; + break; + case VIDEO_CS_2100_HLG: + obsqsv->params.ColourPrimaries = 9; + obsqsv->params.TransferCharacteristics = 18; + obsqsv->params.MatrixCoefficients = 9; + obsqsv->params.ChromaSampleLocTypeTopField = 2; + obsqsv->params.ChromaSampleLocTypeBottomField = 2; + } + + const bool pq = voi->colorspace == VIDEO_CS_2100_PQ; + const bool hlg = voi->colorspace == VIDEO_CS_2100_HLG; + if (pq || hlg) { + const int hdr_nominal_peak_level = + pq ? (int)obs_get_video_hdr_nominal_peak_level() + : (hlg ? 1000 : 0); + + obsqsv->params.DisplayPrimariesX0 = 13250; + obsqsv->params.DisplayPrimariesX1 = 7500; + obsqsv->params.DisplayPrimariesX2 = 34000; + obsqsv->params.DisplayPrimariesY0 = 34500; + obsqsv->params.DisplayPrimariesY1 = 3000; + obsqsv->params.DisplayPrimariesY2 = 16000; + obsqsv->params.WhitePointX = 15635; + obsqsv->params.WhitePointY = 16450; + obsqsv->params.MaxDisplayMasteringLuminance = + hdr_nominal_peak_level * 10000; + obsqsv->params.MinDisplayMasteringLuminance = 0; + + obsqsv->params.MaxContentLightLevel = hdr_nominal_peak_level; + obsqsv->params.MaxPicAverageLightLevel = hdr_nominal_peak_level; + } /* internal convenience parameter, overrides rate control param * XXX: Deprecated */ @@ -489,16 +670,22 @@ else if (astrcmpi(rate_control, "LA_CBR") == 0) obsqsv->params.nRateControl = MFX_RATECONTROL_LA_HRD; - if (astrcmpi(latency, "ultra-low") == 0) { - obsqsv->params.nAsyncDepth = 1; - obsqsv->params.nLADEPTH = (mfxU16)0; - } else if (astrcmpi(latency, "low") == 0) { - obsqsv->params.nAsyncDepth = 4; - obsqsv->params.nLADEPTH = - (mfxU16)(voi->fps_num / voi->fps_den / 2); - } else if (astrcmpi(latency, "normal") == 0) { + if (obsqsv->codec == QSV_CODEC_AV1) { obsqsv->params.nAsyncDepth = 4; - obsqsv->params.nLADEPTH = (mfxU16)(voi->fps_num / voi->fps_den); + obsqsv->params.nLADEPTH = 0; + } else { + if (astrcmpi(latency, "ultra-low") == 0) { + obsqsv->params.nAsyncDepth = 1; + obsqsv->params.nLADEPTH = (mfxU16)0; + } else if (astrcmpi(latency, "low") == 0) { + obsqsv->params.nAsyncDepth = 4; + obsqsv->params.nLADEPTH = + (mfxU16)(voi->fps_num / voi->fps_den / 2); + } else if (astrcmpi(latency, "normal") == 0) { + obsqsv->params.nAsyncDepth = 4; + obsqsv->params.nLADEPTH = + (mfxU16)(voi->fps_num / voi->fps_den); + } } if (obsqsv->params.nLADEPTH > 0) { @@ -510,9 +697,18 @@ obsqsv->params.nAccuracy = (mfxU16)accuracy; obsqsv->params.nConvergence = (mfxU16)convergence; - obsqsv->params.nQPI = (mfxU16)qpi; - obsqsv->params.nQPP = (mfxU16)qpp; - obsqsv->params.nQPB = (mfxU16)qpb; + if (ver == 1) { + obsqsv->params.nQPI = (mfxU16)qpi; + obsqsv->params.nQPP = (mfxU16)qpp; + obsqsv->params.nQPB = (mfxU16)qpb; + } else { + int actual_cqp = cqp; + if (obsqsv->codec == QSV_CODEC_AV1) + actual_cqp *= 4; + obsqsv->params.nQPI = actual_cqp; + obsqsv->params.nQPP = actual_cqp; + obsqsv->params.nQPB = actual_cqp; + } obsqsv->params.nTargetBitRate = (mfxU16)target_bitrate; obsqsv->params.nMaxBitRate = (mfxU16)max_bitrate; obsqsv->params.nWidth = (mfxU16)width; @@ -572,6 +768,28 @@ return true; } +static void load_hevc_headers(struct obs_qsv *obsqsv) +{ + DARRAY(uint8_t) header; + DARRAY(uint8_t) sei; + + da_init(header); + da_init(sei); + + uint8_t *pVPS, *pSPS, *pPPS; + uint16_t nVPS, nSPS, nPPS; + qsv_hevc_encoder_headers(obsqsv->context, &pVPS, &pSPS, &pPPS, &nVPS, + &nSPS, &nPPS); + da_push_back_array(header, pVPS, nVPS); + da_push_back_array(header, pSPS, nSPS); + da_push_back_array(header, pPPS, nPPS); + + obsqsv->extra_data = header.array; + obsqsv->extra_data_size = header.num; + obsqsv->sei = sei.array; + obsqsv->sei_size = sei.num; +} + static void load_headers(struct obs_qsv *obsqsv) { DARRAY(uint8_t) header; @@ -587,9 +805,13 @@ uint8_t *pSPS, *pPPS; uint16_t nSPS, nPPS; + qsv_encoder_headers(obsqsv->context, &pSPS, &pPPS, &nSPS, &nPPS); da_push_back_array(header, pSPS, nSPS); - da_push_back_array(header, pPPS, nPPS); + + // AV1 does not need PPS + if (obsqsv->codec != QSV_CODEC_AV1) + da_push_back_array(header, pPPS, nPPS); obsqsv->extra_data = header.array; obsqsv->extra_data_size = header.num; @@ -600,43 +822,43 @@ static bool obs_qsv_update(void *data, obs_data_t *settings) { struct obs_qsv *obsqsv = data; - bool success = update_settings(obsqsv, settings); - int ret; - - if (success) { - AcquireSRWLockExclusive(&g_QsvLock); - - ret = qsv_encoder_reconfig(obsqsv->context, &obsqsv->params); - if (ret != 0) - warn("Failed to reconfigure: %d", ret); - - ReleaseSRWLockExclusive(&g_QsvLock); + obsqsv->params.nTargetBitRate = + (mfxU16)obs_data_get_int(settings, "bitrate"); - return ret == 0; + if (!qsv_encoder_reconfig(obsqsv->context, &obsqsv->params)) { + warn("Failed to reconfigure"); + return false; } - return false; + return true; } -static void *obs_qsv_create(obs_data_t *settings, obs_encoder_t *encoder) +static void *obs_qsv_create(enum qsv_codec codec, obs_data_t *settings, + obs_encoder_t *encoder) { struct obs_qsv *obsqsv = bzalloc(sizeof(struct obs_qsv)); obsqsv->encoder = encoder; + obsqsv->codec = codec; video_t *video = obs_encoder_video(encoder); const struct video_output_info *voi = video_output_get_info(video); switch (voi->format) { case VIDEO_FORMAT_I010: case VIDEO_FORMAT_P010: - const char *const text = obs_module_text("10bitUnsupportedAvc"); - obs_encoder_set_last_error(encoder, text); - error("%s", text); - bfree(obsqsv); - return NULL; + if (codec == QSV_CODEC_AVC) { + const char *const text = + obs_module_text("10bitUnsupportedAvc"); + obs_encoder_set_last_error(encoder, text); + error("%s", text); + bfree(obsqsv); + return NULL; + } + obsqsv->params.video_fmt_10bit = true; + break; default: switch (voi->colorspace) { case VIDEO_CS_2100_PQ: - case VIDEO_CS_2100_HLG: + case VIDEO_CS_2100_HLG: { const char *const text = obs_module_text("8bitUnsupportedHdr"); obs_encoder_set_last_error(encoder, text); @@ -644,15 +866,18 @@ bfree(obsqsv); return NULL; } + } } if (update_settings(obsqsv, settings)) { AcquireSRWLockExclusive(&g_QsvLock); - obsqsv->context = qsv_encoder_open(&obsqsv->params); + obsqsv->context = qsv_encoder_open(&obsqsv->params, codec); ReleaseSRWLockExclusive(&g_QsvLock); if (obsqsv->context == NULL) warn("qsv failed to load"); + else if (obsqsv->codec == QSV_CODEC_HEVC) + load_hevc_headers(obsqsv); else load_headers(obsqsv); } else { @@ -697,6 +922,21 @@ return obsqsv; } +static void *obs_qsv_create_h264(obs_data_t *settings, obs_encoder_t *encoder) +{ + return obs_qsv_create(QSV_CODEC_AVC, settings, encoder); +} + +static void *obs_qsv_create_av1(obs_data_t *settings, obs_encoder_t *encoder) +{ + return obs_qsv_create(QSV_CODEC_AV1, settings, encoder); +} + +static void *obs_qsv_create_hevc(obs_data_t *settings, obs_encoder_t *encoder) +{ + return obs_qsv_create(QSV_CODEC_HEVC, settings, encoder); +} + static HANDLE get_lib(const char *lib) { HMODULE mod = GetModuleHandleA(lib); @@ -711,76 +951,76 @@ typedef HRESULT(WINAPI *CREATEDXGIFACTORY1PROC)(REFIID, void **); -static bool is_intel_gpu_primary() +static void *obs_qsv_create_tex(enum qsv_codec codec, obs_data_t *settings, + obs_encoder_t *encoder, const char *fallback_id) { - HMODULE dxgi = get_lib("DXGI.dll"); - CREATEDXGIFACTORY1PROC create_dxgi; - IDXGIFactory1 *factory; - IDXGIAdapter *adapter; - DXGI_ADAPTER_DESC desc; - HRESULT hr; - - if (!dxgi) { - return false; - } - create_dxgi = (CREATEDXGIFACTORY1PROC)GetProcAddress( - dxgi, "CreateDXGIFactory1"); - - if (!create_dxgi) { - blog(LOG_INFO, "Failed to load D3D11/DXGI procedures"); - return false; - } - - hr = create_dxgi(&IID_IDXGIFactory1, &factory); - if (FAILED(hr)) { - blog(LOG_INFO, "CreateDXGIFactory1 failed"); - return false; - } + struct obs_video_info ovi; + obs_get_video_info(&ovi); - hr = factory->lpVtbl->EnumAdapters(factory, 0, &adapter); - factory->lpVtbl->Release(factory); - if (FAILED(hr)) { - blog(LOG_INFO, "EnumAdapters failed"); - return false; + if (!adaptersovi.adapter.is_intel) { + blog(LOG_INFO, + ">>> app not on intel GPU, fall back to old qsv encoder"); + return obs_encoder_create_rerouted(encoder, + (const char *)fallback_id); } - hr = adapter->lpVtbl->GetDesc(adapter, &desc); - adapter->lpVtbl->Release(adapter); - if (FAILED(hr)) { - blog(LOG_INFO, "GetDesc failed"); - return false; + if (codec == QSV_CODEC_AV1 && !adaptersovi.adapter.supports_av1) { + blog(LOG_INFO, + ">>> cap on different device, fall back to non-texture sharing AV1 qsv encoder"); + return obs_encoder_create_rerouted(encoder, + (const char *)fallback_id); } - /*check whether adapter 0 is Intel*/ - if (desc.VendorId == 0x8086) { - return true; - } else { - return false; - } -} + bool gpu_texture_active = obs_nv12_tex_active(); -static void *obs_qsv_create_tex(obs_data_t *settings, obs_encoder_t *encoder) -{ - if (!is_intel_gpu_primary()) { - blog(LOG_INFO, - ">>> app not on intel GPU, fall back to old qsv encoder"); - return obs_encoder_create_rerouted(encoder, "obs_qsv11_soft"); - } + if (codec != QSV_CODEC_AVC) + gpu_texture_active = gpu_texture_active || + obs_p010_tex_active(); - if (!obs_nv12_tex_active()) { + if (!gpu_texture_active) { blog(LOG_INFO, - ">>> nv12 tex not active, fall back to old qsv encoder"); - return obs_encoder_create_rerouted(encoder, "obs_qsv11_soft"); + ">>> gpu tex not active, fall back to old qsv encoder"); + return obs_encoder_create_rerouted(encoder, + (const char *)fallback_id); } if (obs_encoder_scaling_enabled(encoder)) { blog(LOG_INFO, ">>> encoder scaling active, fall back to old qsv encoder"); - return obs_encoder_create_rerouted(encoder, "obs_qsv11_soft"); + return obs_encoder_create_rerouted(encoder, + (const char *)fallback_id); } blog(LOG_INFO, ">>> new qsv encoder"); - return obs_qsv_create(settings, encoder); + return obs_qsv_create(codec, settings, encoder); +} + +static void *obs_qsv_create_tex_h264(obs_data_t *settings, + obs_encoder_t *encoder) +{ + return obs_qsv_create_tex(QSV_CODEC_AVC, settings, encoder, + "obs_qsv11_soft"); +} + +static void *obs_qsv_create_tex_h264_v2(obs_data_t *settings, + obs_encoder_t *encoder) +{ + return obs_qsv_create_tex(QSV_CODEC_AVC, settings, encoder, + "obs_qsv11_soft_v2"); +} + +static void *obs_qsv_create_tex_av1(obs_data_t *settings, + obs_encoder_t *encoder) +{ + return obs_qsv_create_tex(QSV_CODEC_AV1, settings, encoder, + "obs_qsv11_av1_soft"); +} + +static void *obs_qsv_create_tex_hevc(obs_data_t *settings, + obs_encoder_t *encoder) +{ + return obs_qsv_create_tex(QSV_CODEC_HEVC, settings, encoder, + "obs_qsv11_hevc_soft"); } static bool obs_qsv_extra_data(void *data, uint8_t **extra_data, size_t *size) @@ -812,12 +1052,20 @@ return format == VIDEO_FORMAT_NV12; } -static inline void cap_resolution(obs_encoder_t *encoder, +static inline bool valid_av1_format(enum video_format format) +{ + return format == VIDEO_FORMAT_NV12 || format == VIDEO_FORMAT_P010; +} + +static inline void cap_resolution(struct obs_qsv *obsqsv, struct video_scale_info *info) { enum qsv_cpu_platform qsv_platform = qsv_get_cpu_platform(); - uint32_t width = obs_encoder_get_width(encoder); - uint32_t height = obs_encoder_get_height(encoder); + uint32_t width = obs_encoder_get_width(obsqsv->encoder); + uint32_t height = obs_encoder_get_height(obsqsv->encoder); + + if (qsv_encoder_is_dgpu(obsqsv->context)) + qsv_platform = QSV_CPU_PLATFORM_UNKNOWN; info->height = height; info->width = width; @@ -847,7 +1095,25 @@ } info->format = pref_format; - cap_resolution(obsqsv->encoder, info); + cap_resolution(obsqsv, info); +} + +static void obs_qsv_video_plus_hdr_info(void *data, + struct video_scale_info *info) +{ + struct obs_qsv *obsqsv = data; + enum video_format pref_format; + + pref_format = obs_encoder_get_preferred_video_format(obsqsv->encoder); + + if (!valid_av1_format(pref_format)) { + pref_format = valid_av1_format(info->format) + ? info->format + : VIDEO_FORMAT_NV12; + } + + info->format = pref_format; + cap_resolution(obsqsv, info); } static mfxU64 ts_obs_to_mfx(int64_t ts, const struct video_output_info *voi) @@ -962,6 +1228,128 @@ g_bFirst = false; } +static void parse_packet_av1(struct obs_qsv *obsqsv, + struct encoder_packet *packet, mfxBitstream *pBS, + const struct video_output_info *voi, + bool *received_packet) +{ + if (pBS == NULL || pBS->DataLength == 0) { + *received_packet = false; + return; + } + + da_resize(obsqsv->packet_data, 0); + da_push_back_array(obsqsv->packet_data, &pBS->DatapBS->DataOffset, + pBS->DataLength); + + packet->data = obsqsv->packet_data.array; + packet->size = obsqsv->packet_data.num; + packet->type = OBS_ENCODER_VIDEO; + packet->pts = ts_mfx_to_obs((mfxI64)pBS->TimeStamp, voi); + packet->keyframe = (pBS->FrameType & MFX_FRAMETYPE_IDR); + + uint16_t frameType = pBS->FrameType; + uint8_t priority; + + if (frameType & MFX_FRAMETYPE_I) + priority = OBS_NAL_PRIORITY_HIGHEST; + else if ((frameType & MFX_FRAMETYPE_P) || + (frameType & MFX_FRAMETYPE_REF)) + priority = OBS_NAL_PRIORITY_HIGH; + else + priority = OBS_NAL_PRIORITY_DISPOSABLE; + + packet->priority = priority; + + bool pFrame = pBS->FrameType & MFX_FRAMETYPE_P; + + packet->dts = ts_mfx_to_obs(pBS->DecodeTimeStamp, voi); + +#if 0 + info("parse packet:\n" + "\tFrameType: %d\n" + "\tpts: %d\n" + "\tdts: %d", + iType, packet->pts, packet->dts); +#endif + + *received_packet = true; + pBS->DataLength = 0; + + g_bFirst = false; +} + +static void parse_packet_hevc(struct obs_qsv *obsqsv, + struct encoder_packet *packet, mfxBitstream *pBS, + const struct video_output_info *voi, + bool *received_packet) +{ + bool is_vcl_packet = false; + + if (pBS == NULL || pBS->DataLength == 0) { + *received_packet = false; + return; + } + + da_resize(obsqsv->packet_data, 0); + da_push_back_array(obsqsv->packet_data, &pBS->DatapBS->DataOffset, + pBS->DataLength); + + packet->data = obsqsv->packet_data.array; + packet->size = obsqsv->packet_data.num; + packet->type = OBS_ENCODER_VIDEO; + packet->pts = ts_mfx_to_obs((mfxI64)pBS->TimeStamp, voi); + packet->keyframe = (pBS->FrameType & MFX_FRAMETYPE_IDR); + + uint16_t frameType = pBS->FrameType; + uint8_t priority = OBS_NAL_PRIORITY_DISPOSABLE; + + if (frameType & MFX_FRAMETYPE_I) + priority = OBS_NAL_PRIORITY_HIGHEST; + else if ((frameType & MFX_FRAMETYPE_P) || + (frameType & MFX_FRAMETYPE_REF)) + priority = OBS_NAL_PRIORITY_HIGH; + + packet->priority = priority; + + /* ------------------------------------ */ + + //bool iFrame = pBS->FrameType & MFX_FRAMETYPE_I; + //bool bFrame = pBS->FrameType & MFX_FRAMETYPE_B; + bool pFrame = pBS->FrameType & MFX_FRAMETYPE_P; + + // In case MSDK doesn't support automatic DecodeTimeStamp, do manual + // calculation + if (g_pts2dtsShift >= 0) { + if (g_bFirst) { + packet->dts = packet->pts - 3 * obsqsv->params.nFpsDen; + } else if (pFrame) { + packet->dts = packet->pts - 10 * obsqsv->params.nFpsDen; + g_prevDts = packet->dts; + } else { + packet->dts = g_prevDts + obsqsv->params.nFpsDen; + g_prevDts = packet->dts; + } + } else { + packet->dts = ts_mfx_to_obs(pBS->DecodeTimeStamp, voi); + } + +#if 0 + int iType = iFrame ? 0 : (bFrame ? 1 : (pFrame ? 2 : -1)); + int64_t interval = obsqsv->params.nbFrames + 1; + + info("parse packet:\n" + "\tFrameType: %d\n" + "\tpts: %d\n" + "\tdts: %d", + iType, packet->pts, packet->dts); +#endif + *received_packet = true; + pBS->DataLength = 0; + + g_bFirst = false; +} + static bool obs_qsv_encode(void *data, struct encoder_frame *frame, struct encoder_packet *packet, bool *received_packet) { @@ -998,7 +1386,12 @@ return false; } - parse_packet(obsqsv, packet, pBS, voi, received_packet); + if (obsqsv->codec == QSV_CODEC_AVC) + parse_packet(obsqsv, packet, pBS, voi, received_packet); + else if (obsqsv->codec == QSV_CODEC_AV1) + parse_packet_av1(obsqsv, packet, pBS, voi, received_packet); + else if (obsqsv->codec == QSV_CODEC_HEVC) + parse_packet_hevc(obsqsv, packet, pBS, voi, received_packet); ReleaseSRWLockExclusive(&g_QsvLock); @@ -1041,43 +1434,148 @@ return false; } - parse_packet(obsqsv, packet, pBS, voi, received_packet); + if (obsqsv->codec == QSV_CODEC_AVC) + parse_packet(obsqsv, packet, pBS, voi, received_packet); + else if (obsqsv->codec == QSV_CODEC_AV1) + parse_packet_av1(obsqsv, packet, pBS, voi, received_packet); + else if (obsqsv->codec == QSV_CODEC_HEVC) + parse_packet_hevc(obsqsv, packet, pBS, voi, received_packet); ReleaseSRWLockExclusive(&g_QsvLock); return true; } +struct obs_encoder_info obs_qsv_encoder_tex = { + .id = "obs_qsv11", + .type = OBS_ENCODER_VIDEO, + .codec = "h264", + .get_name = obs_qsv_getname_v1, + .create = obs_qsv_create_tex_h264, + .destroy = obs_qsv_destroy, + .caps = OBS_ENCODER_CAP_DYN_BITRATE | OBS_ENCODER_CAP_PASS_TEXTURE | + OBS_ENCODER_CAP_DEPRECATED, + .encode_texture = obs_qsv_encode_tex, + .update = obs_qsv_update, + .get_properties = obs_qsv_props_h264, + .get_defaults = obs_qsv_defaults_h264_v1, + .get_extra_data = obs_qsv_extra_data, + .get_sei_data = obs_qsv_sei, + .get_video_info = obs_qsv_video_info, +}; + struct obs_encoder_info obs_qsv_encoder = { .id = "obs_qsv11_soft", .type = OBS_ENCODER_VIDEO, .codec = "h264", - .get_name = obs_qsv_getname, - .create = obs_qsv_create, + .get_name = obs_qsv_getname_v1, + .create = obs_qsv_create_h264, .destroy = obs_qsv_destroy, .encode = obs_qsv_encode, .update = obs_qsv_update, - .get_properties = obs_qsv_props, - .get_defaults = obs_qsv_defaults, + .get_properties = obs_qsv_props_h264, + .get_defaults = obs_qsv_defaults_h264_v1, .get_extra_data = obs_qsv_extra_data, .get_sei_data = obs_qsv_sei, .get_video_info = obs_qsv_video_info, - .caps = OBS_ENCODER_CAP_DYN_BITRATE | OBS_ENCODER_CAP_INTERNAL, + .caps = OBS_ENCODER_CAP_DYN_BITRATE | OBS_ENCODER_CAP_INTERNAL | + OBS_ENCODER_CAP_DEPRECATED, }; -struct obs_encoder_info obs_qsv_encoder_tex = { - .id = "obs_qsv11", +struct obs_encoder_info obs_qsv_encoder_tex_v2 = { + .id = "obs_qsv11_v2", .type = OBS_ENCODER_VIDEO, .codec = "h264", .get_name = obs_qsv_getname, - .create = obs_qsv_create_tex, + .create = obs_qsv_create_tex_h264_v2, .destroy = obs_qsv_destroy, .caps = OBS_ENCODER_CAP_DYN_BITRATE | OBS_ENCODER_CAP_PASS_TEXTURE, .encode_texture = obs_qsv_encode_tex, .update = obs_qsv_update, - .get_properties = obs_qsv_props, - .get_defaults = obs_qsv_defaults, + .get_properties = obs_qsv_props_h264_v2, + .get_defaults = obs_qsv_defaults_h264_v2, .get_extra_data = obs_qsv_extra_data, .get_sei_data = obs_qsv_sei, .get_video_info = obs_qsv_video_info, }; + +struct obs_encoder_info obs_qsv_encoder_v2 = { + .id = "obs_qsv11_soft_v2", + .type = OBS_ENCODER_VIDEO, + .codec = "h264", + .get_name = obs_qsv_getname, + .create = obs_qsv_create_h264, + .destroy = obs_qsv_destroy, + .encode = obs_qsv_encode, + .update = obs_qsv_update, + .get_properties = obs_qsv_props_h264_v2, + .get_defaults = obs_qsv_defaults_h264_v2, + .get_extra_data = obs_qsv_extra_data, + .get_sei_data = obs_qsv_sei, + .get_video_info = obs_qsv_video_info, + .caps = OBS_ENCODER_CAP_DYN_BITRATE | OBS_ENCODER_CAP_INTERNAL, +}; + +struct obs_encoder_info obs_qsv_av1_encoder_tex = { + .id = "obs_qsv11_av1", + .type = OBS_ENCODER_VIDEO, + .codec = "av1", + .get_name = obs_qsv_getname_av1, + .create = obs_qsv_create_tex_av1, + .destroy = obs_qsv_destroy, + .caps = OBS_ENCODER_CAP_DYN_BITRATE | OBS_ENCODER_CAP_PASS_TEXTURE, + .encode_texture = obs_qsv_encode_tex, + .update = obs_qsv_update, + .get_properties = obs_qsv_props_av1, + .get_defaults = obs_qsv_defaults_av1, + .get_extra_data = obs_qsv_extra_data, + .get_video_info = obs_qsv_video_plus_hdr_info, +}; + +struct obs_encoder_info obs_qsv_av1_encoder = { + .id = "obs_qsv11_av1_soft", + .type = OBS_ENCODER_VIDEO, + .codec = "av1", + .get_name = obs_qsv_getname_av1, + .create = obs_qsv_create_av1, + .destroy = obs_qsv_destroy, + .encode = obs_qsv_encode, + .update = obs_qsv_update, + .get_properties = obs_qsv_props_av1, + .get_defaults = obs_qsv_defaults_av1, + .get_extra_data = obs_qsv_extra_data, + .get_video_info = obs_qsv_video_plus_hdr_info, + .caps = OBS_ENCODER_CAP_DYN_BITRATE | OBS_ENCODER_CAP_INTERNAL, +}; + +struct obs_encoder_info obs_qsv_hevc_encoder_tex = { + .id = "obs_qsv11_hevc", + .type = OBS_ENCODER_VIDEO, + .codec = "hevc", + .get_name = obs_qsv_getname_hevc, + .create = obs_qsv_create_tex_hevc, + .destroy = obs_qsv_destroy, + .caps = OBS_ENCODER_CAP_DYN_BITRATE | OBS_ENCODER_CAP_PASS_TEXTURE, + .encode_texture = obs_qsv_encode_tex, + .update = obs_qsv_update, + .get_properties = obs_qsv_props_hevc, + .get_defaults = obs_qsv_defaults_hevc, + .get_extra_data = obs_qsv_extra_data, + .get_video_info = obs_qsv_video_plus_hdr_info, +}; + +struct obs_encoder_info obs_qsv_hevc_encoder = { + .id = "obs_qsv11_hevc_soft", + .type = OBS_ENCODER_VIDEO, + .codec = "hevc", + .get_name = obs_qsv_getname_hevc, + .create = obs_qsv_create_hevc, + .destroy = obs_qsv_destroy, + .encode = obs_qsv_encode, + .update = obs_qsv_update, + .get_properties = obs_qsv_props_hevc, + .get_defaults = obs_qsv_defaults_hevc, + .get_extra_data = obs_qsv_extra_data, + .get_video_info = obs_qsv_video_plus_hdr_info, + .caps = OBS_ENCODER_CAP_DYN_BITRATE | OBS_ENCODER_CAP_INTERNAL, +};
View file
obs-studio-28.1.2.tar.xz/plugins/obs-vst/VSTPlugin.cpp -> obs-studio-29.0.0.tar.xz/plugins/obs-vst/VSTPlugin.cpp
Changed
@@ -96,14 +96,14 @@ numChannels = (std::max)((size_t)0, count); if (numChannels > 0) { - inputs = (float **)malloc(sizeof(float *) * numChannels); - outputs = (float **)malloc(sizeof(float *) * numChannels); - channelrefs = (float **)malloc(sizeof(float *) * numChannels); + inputs = (float **)bmalloc(sizeof(float *) * numChannels); + outputs = (float **)bmalloc(sizeof(float *) * numChannels); + channelrefs = (float **)bmalloc(sizeof(float *) * numChannels); for (size_t channel = 0; channel < numChannels; channel++) { inputschannel = - (float *)malloc(sizeof(float) * blocksize); + (float *)bmalloc(sizeof(float) * blocksize); outputschannel = - (float *)malloc(sizeof(float) * blocksize); + (float *)bmalloc(sizeof(float) * blocksize); } } } @@ -112,30 +112,30 @@ { for (size_t channel = 0; channel < numChannels; channel++) { if (inputs && inputschannel) { - free(inputschannel); + bfree(inputschannel); inputschannel = NULL; } if (outputs && outputschannel) { - free(outputschannel); + bfree(outputschannel); outputschannel = NULL; } } if (inputs) { - free(inputs); + bfree(inputs); inputs = NULL; } if (outputs) { - free(outputs); + bfree(outputs); outputs = NULL; } if (channelrefs) { - free(channelrefs); + bfree(channelrefs); channelrefs = NULL; } numChannels = 0; } -void VSTPlugin::loadEffectFromPath(std::string path) +void VSTPlugin::loadEffectFromPath(const std::string &path) { if (this->pluginPath.compare(path) != 0) { unloadEffect(); @@ -309,7 +309,7 @@ unloadLibrary(); - pluginPath = ""; + pluginPath.clear(); } bool VSTPlugin::isEditorOpen() @@ -403,7 +403,7 @@ } } -void VSTPlugin::setChunk(std::string data) +void VSTPlugin::setChunk(const std::string &data) { if (!effect) { return;
View file
obs-studio-28.1.2.tar.xz/plugins/obs-vst/headers/VSTPlugin.h -> obs-studio-29.0.0.tar.xz/plugins/obs-vst/headers/VSTPlugin.h
Changed
@@ -88,11 +88,11 @@ public: VSTPlugin(obs_source_t *sourceContext); ~VSTPlugin(); - void loadEffectFromPath(std::string path); + void loadEffectFromPath(const std::string &path); void unloadEffect(); std::string getEffectPath(); std::string getChunk(); - void setChunk(std::string data); + void setChunk(const std::string &data); void setProgram(const int programNumber); int getProgram(); void getSourceNames();
View file
obs-studio-28.1.2.tar.xz/plugins/obs-vst/obs-vst.cpp -> obs-studio-29.0.0.tar.xz/plugins/obs-vst/obs-vst.cpp
Changed
@@ -111,7 +111,20 @@ const char *path = obs_data_get_string(settings, "plugin_path"); - if (strcmp(path, "") == 0) { +#ifdef __linux__ + // Migrate freedesktop.org Flatpak runtime 21.08 VST paths to 22.08. + if (QFile::exists("/.flatpak-info") && + QString(path).startsWith("/app/extensions/Plugins/lxvst")) { + QString newPath(path); + newPath.replace("/app/extensions/Plugins/lxvst", + "/app/extensions/Plugins/vst"); + obs_data_set_string(settings, "plugin_path", + newPath.toStdString().c_str()); + path = obs_data_get_string(settings, "plugin_path"); + } +#endif + + if (!*path) { vstPlugin->unloadEffect(); return; } @@ -121,10 +134,10 @@ const char *chunkHash = obs_data_get_string(settings, "chunk_hash"); const char *chunkData = obs_data_get_string(settings, "chunk_data"); - bool chunkHashesMatch = chunkHash && strlen(chunkHash) > 0 && + bool chunkHashesMatch = chunkHash && *chunkHash && hash.compare(chunkHash) == 0; - if (chunkData && strlen(chunkData) > 0 && - (chunkHashesMatch || !chunkHash || strlen(chunkHash) == 0)) { + if (chunkData && *chunkData && + (chunkHashesMatch || !chunkHash || !*chunkHash)) { vstPlugin->setChunk(std::string(chunkData)); } }
View file
obs-studio-28.1.2.tar.xz/plugins/obs-websocket/.github/ISSUE_TEMPLATE/bug_report.yaml -> obs-studio-29.0.0.tar.xz/plugins/obs-websocket/.github/ISSUE_TEMPLATE/bug_report.yaml
Changed
@@ -28,10 +28,8 @@ - macOS 10.14 - macOS 10.13 - Ubuntu 22.04 LTS - - Ubuntu 21.04 - Ubuntu 20.10 - Ubuntu 20.04 LTS - - Ubuntu 18.04 LTS - Other validations: required: true @@ -49,16 +47,10 @@ label: OBS Studio Version description: What version of OBS Studio are you using? options: - - 28.0.0 + - 29.0.x + - 28.1.x + - 28.0.x - 27.2.4 - - 27.2.3 - - 27.2.2 - - 27.2.1 - - 27.2.0 - - 27.1.3 - - 27.1.1 - - 27.1.0 - - 27.0.1 - Git - Other validations: @@ -76,9 +68,9 @@ label: obs-websocket Version description: What version of obs-websocket are you using? options: + - 5.1.0 - 5.0.1 - 5.0.0 - - 5.0.0-beta1 - Git validations: required: true
View file
obs-studio-28.1.2.tar.xz/plugins/obs-websocket/CMakeLists.txt -> obs-studio-29.0.0.tar.xz/plugins/obs-websocket/CMakeLists.txt
Changed
@@ -1,4 +1,4 @@ -project(obs-websocket VERSION 5.0.1) +project(obs-websocket VERSION 5.1.0) set(OBS_WEBSOCKET_RPC_VERSION 1) option(ENABLE_WEBSOCKET "Enable building OBS with websocket plugin" ON)
View file
obs-studio-28.1.2.tar.xz/plugins/obs-websocket/README.md -> obs-studio-29.0.0.tar.xz/plugins/obs-websocket/README.md
Changed
@@ -31,21 +31,30 @@ ### Client software +- Macro Deck(https://www.macrodeck.org/) - Touch Portal(https://www.touch-portal.com/) - Twitchat(https://twitchat.fr/) - OBS-web(https://github.com/Niek/obs-web) - hosted client at obs-web.niek.tv/(http://obs-web.niek.tv/) +- Streamer.bot(https://streamer.bot/) +- Deckboard(https://deckboard.app/) +- OBS Blade(https://github.com/Kounex/obs_blade) +- Aitum(https://aitum.tv/) +- Kruiz Control(https://github.com/Kruiser8/Kruiz-Control) +- Bitfocus Companion Module(https://bitfocus.io/companion/) ### Client libraries (for developers) Here's a list of available language APIs for obs-websocket: - Python 3.7+ (Asyncio): simpleobsws(https://github.com/IRLToolkit/simpleobsws/tree/master) by IRLToolkit +- Python 3.10+ (Non-Asyncio): obsws-python(https://pypi.org/project/obsws-python) by aatikturk and onyx-and-iris - Rust: obws(https://github.com/dnaka91/obws) by dnaka91 - Godot 3.4.x: obs-websocket-gd(https://github.com/you-win/obs-websocket-gd) by you-win - Javascript (Node and web): obs-websocket-js(https://github.com/obs-websocket-community-projects/obs-websocket-js) by OBS Websocket Community - C (uses obs-websocket-js): v8-libwebsocket-obs-websocket(https://github.com/dgatwood/v8-libwebsocket-obs-websocket) - Go: goobs(https://github.com/andreykaipov/goobs) by andreykaipov - Dart/Flutter (can target all supported platforms): obs_websocket(https://github.com/faithoflifedev/obs_websocket) by faithoflifedev +- Java: obs-websocket-java(https://github.com/obs-websocket-community-projects/obs-websocket-java) by OBS Websocket Community The 5.x server is a typical WebSocket server running by default on port 4455 (the port number can be changed in the Settings dialog under `Tools`). The protocol we use is documented in PROTOCOL.md(docs/generated/protocol.md).
View file
obs-studio-28.1.2.tar.xz/plugins/obs-websocket/data/locale/en-US.ini -> obs-studio-29.0.0.tar.xz/plugins/obs-websocket/data/locale/en-US.ini
Changed
@@ -1,6 +1,6 @@ OBSWebSocket.Plugin.Description="Remote-control of OBS Studio through WebSocket" -OBSWebSocket.Settings.DialogTitle="obs-websocket Settings" +OBSWebSocket.Settings.DialogTitle="WebSocket Server Settings" OBSWebSocket.Settings.PluginSettingsTitle="Plugin Settings" OBSWebSocket.Settings.ServerEnable="Enable WebSocket server"
View file
obs-studio-28.1.2.tar.xz/plugins/obs-websocket/data/locale/fa-IR.ini -> obs-studio-29.0.0.tar.xz/plugins/obs-websocket/data/locale/fa-IR.ini
Changed
@@ -1,3 +1,43 @@ +OBSWebSocket.Plugin.Description="کنترل از راه دور OBS Studio از طریق WebSocket" +OBSWebSocket.Settings.DialogTitle="تنظیمات obs-سوکت وب" +OBSWebSocket.Settings.PluginSettingsTitle="تنظیمات پلاگین" +OBSWebSocket.Settings.ServerEnable="سرور سوکت وب را فعال کنید" +OBSWebSocket.Settings.AlertsEnable="هشدارهای سینی سیستم را فعال کنید" +OBSWebSocket.Settings.DebugEnable="فعال کردن گزارش اشکال زدایی" +OBSWebSocket.Settings.DebugEnableHoverText="ثبت اشکال زدایی را برای نمونه فعلی OBS فعال می کند. در بارگذاری ادامه نمییابد.\n برای فعال کردن در بارگذاری از --websocket_debug استفاده کنید." +OBSWebSocket.Settings.ServerSettingsTitle="تنظیمات سرور" +OBSWebSocket.Settings.AuthRequired="فعال کردن احراز هویت" +OBSWebSocket.Settings.Password="رمز سرور" +OBSWebSocket.Settings.GeneratePassword="ایجاد رمز عبور" +OBSWebSocket.Settings.ServerPort="پورت سرور" +OBSWebSocket.Settings.ShowConnectInfo="نمایش اطلاعات اتصال" +OBSWebSocket.Settings.ShowConnectInfoWarningTitle="هشدار: در حال حاضر زنده است" +OBSWebSocket.Settings.ShowConnectInfoWarningMessage="به نظر می رسد که یک خروجی (جریان، ضبط و غیره) در حال حاضر فعال است." +OBSWebSocket.Settings.ShowConnectInfoWarningInfoText="آیا مطمئن هستید که می خواهید اطلاعات اتصال خود را نشان دهید؟" +OBSWebSocket.Settings.Save.UserPasswordWarningTitle="هشدار: مشکل امنیتی احتمالی" +OBSWebSocket.Settings.Save.UserPasswordWarningMessage="obs-websocket رمز عبور سرور را به صورت متن ساده ذخیره می کند. استفاده از رمز عبور تولید شده توسط obs-websocket بسیار توصیه می شود." +OBSWebSocket.Settings.Save.UserPasswordWarningInfoText="آیا مطمئن هستید که می خواهید از رمز عبور خود استفاده کنید؟" +OBSWebSocket.Settings.Save.PasswordInvalidErrorTitle="خطا: پیکربندی نامعتبر است" +OBSWebSocket.Settings.Save.PasswordInvalidErrorMessage="باید از رمز عبور 6 کاراکتر یا بیشتر استفاده کنید." +OBSWebSocket.SessionTable.Title="جلسات سوکت وب متصل" +OBSWebSocket.SessionTable.RemoteAddressColumnTitle="آدرس از راه دور" +OBSWebSocket.SessionTable.SessionDurationColumnTitle="مدت زمان جلسه" +OBSWebSocket.SessionTable.MessagesInOutColumnTitle="پیام های ورودی/خارجی" +OBSWebSocket.SessionTable.IdentifiedTitle="تایید هویت شده" OBSWebSocket.SessionTable.KickButtonColumnTitle="لگد زدن؟" OBSWebSocket.SessionTable.KickButtonText="اخراج" +OBSWebSocket.ConnectInfo.DialogTitle="اطلاعات اتصال سوکت وب" OBSWebSocket.ConnectInfo.CopyText="رونوشت" +OBSWebSocket.ConnectInfo.ServerIp="IP سرور (بهترین حدس)" +OBSWebSocket.ConnectInfo.ServerPort="پورت سرور" +OBSWebSocket.ConnectInfo.ServerPassword="رمز سرور" +OBSWebSocket.ConnectInfo.ServerPasswordPlaceholderText="احراز غیر فعال" +OBSWebSocket.ConnectInfo.QrTitle="QR را وصل کنید" +OBSWebSocket.TrayNotification.Identified.Title="اتصال سوکت وب جدید" +OBSWebSocket.TrayNotification.Identified.Body="سرویس گیرنده %1 شناسایی شد." +OBSWebSocket.TrayNotification.AuthenticationFailed.Title="خرابی تأیید اعتبار سوکت وب" +OBSWebSocket.TrayNotification.AuthenticationFailed.Body="سرویس گیرنده %1 احراز هویت نشد." +OBSWebSocket.TrayNotification.Disconnected.Title="سرویس گیرنده سوکت وب قطع شد" +OBSWebSocket.TrayNotification.Disconnected.Body="سرویس گیرنده %1 قطع شد." +OBSWebSocket.Server.StartFailed.Title="خرابی سرور سوکت وب" +OBSWebSocket.Server.StartFailed.Message="سرور WebSocket راهاندازی نشد. درگاه TCP % 1 ممکن است قبلاً در جای دیگری در این سیستم توسط برنامه دیگری استفاده شده باشد. یک پورت TCP دیگر را در تنظیمات سرور WebSocket تنظیم کنید، یا هر برنامهای را که میتواند از این پورت استفاده کند متوقف کنید.\n پیام خطا: %2"
View file
obs-studio-28.1.2.tar.xz/plugins/obs-websocket/data/locale/pt-BR.ini -> obs-studio-29.0.0.tar.xz/plugins/obs-websocket/data/locale/pt-BR.ini
Changed
@@ -22,7 +22,7 @@ OBSWebSocket.SessionTable.Title="Sessões WebSocket Conectadas" OBSWebSocket.SessionTable.RemoteAddressColumnTitle="Endereço Remoto" OBSWebSocket.SessionTable.SessionDurationColumnTitle="Duração de Sessão" -OBSWebSocket.SessionTable.MessagesInOutColumnTitle="Mengsagens de Entrada/Saída" +OBSWebSocket.SessionTable.MessagesInOutColumnTitle="Mensagens" OBSWebSocket.SessionTable.IdentifiedTitle="Identificada" OBSWebSocket.SessionTable.KickButtonColumnTitle="Expulsar?" OBSWebSocket.SessionTable.KickButtonText="Expulsar"
View file
obs-studio-28.1.2.tar.xz/plugins/obs-websocket/data/locale/ro-RO.ini -> obs-studio-29.0.0.tar.xz/plugins/obs-websocket/data/locale/ro-RO.ini
Changed
@@ -12,11 +12,11 @@ OBSWebSocket.Settings.ServerPort="Portul serverului" OBSWebSocket.Settings.ShowConnectInfo="Afișează informațiile de conectare" OBSWebSocket.Settings.ShowConnectInfoWarningTitle="Avertisment: În prezent în direct" -OBSWebSocket.Settings.ShowConnectInfoWarningMessage="Se pare că o ieșire (flux, înregistrare etc.) este activă în prezent." -OBSWebSocket.Settings.ShowConnectInfoWarningInfoText="Ești sigur că vrei să-ți arăți informațiile de conectare?" +OBSWebSocket.Settings.ShowConnectInfoWarningMessage="Se pare că un output (transmisiune, înregistrare etc.) este activ în prezent." +OBSWebSocket.Settings.ShowConnectInfoWarningInfoText="Sigur vrei să afișezi informațiile de conectare?" OBSWebSocket.Settings.Save.UserPasswordWarningTitle="Avertisment: Potențială problemă de securitate" OBSWebSocket.Settings.Save.UserPasswordWarningMessage="obs-websocket stochează parola serverului ca text simplu. Este foarte recomandat să folosiți o parolă generată de obs-websocket." -OBSWebSocket.Settings.Save.UserPasswordWarningInfoText="Ești sigur că vrei să-ți folosești propria parolă?" +OBSWebSocket.Settings.Save.UserPasswordWarningInfoText="Sigur vrei să-ți folosești propria parolă?" OBSWebSocket.Settings.Save.PasswordInvalidErrorTitle="Eroare: Configurație invalidă" OBSWebSocket.Settings.Save.PasswordInvalidErrorMessage="Trebuie să folosești o parolă care să aibă 6 sau mai multe caractere." OBSWebSocket.SessionTable.Title="Sesiuni WebSocket conectate"
View file
obs-studio-29.0.0.tar.xz/plugins/obs-websocket/data/locale/vi-VN.ini
Added
@@ -0,0 +1,7 @@ +OBSWebSocket.Settings.PluginSettingsTitle="Thiết đặt trình cắm" +OBSWebSocket.Settings.ServerEnable="Bật máy chủ WebSocket" +OBSWebSocket.Settings.ServerSettingsTitle="Thiết đặt máy chủ" +OBSWebSocket.Settings.Password="Mật khẩu máy chủ" +OBSWebSocket.Settings.GeneratePassword="Tạo mật khẩu" +OBSWebSocket.Settings.ServerPort="Cổng máy chủ" +OBSWebSocket.Settings.ShowConnectInfo="Hiện thông tin kết nối"
View file
obs-studio-28.1.2.tar.xz/plugins/obs-websocket/docs/docs/generate_md.py -> obs-studio-29.0.0.tar.xz/plugins/obs-websocket/docs/docs/generate_md.py
Changed
@@ -9,7 +9,9 @@ 'WebSocketCloseCode', 'RequestBatchExecutionType', 'RequestStatus', - 'EventSubscription' + 'EventSubscription', + 'ObsMediaInputAction', + 'ObsOutputState' categoryOrder =
View file
obs-studio-28.1.2.tar.xz/plugins/obs-websocket/docs/docs/partials/introduction.md -> obs-studio-29.0.0.tar.xz/plugins/obs-websocket/docs/docs/partials/introduction.md
Changed
@@ -1,5 +1,5 @@ -# obs-websocket 5.0.1 Protocol +# obs-websocket 5.1.0 Protocol ## Main Table of Contents @@ -19,6 +19,9 @@ - RequestResponse (OpCode 7)(#requestresponse-opcode-7) - RequestBatch (OpCode 8)(#requestbatch-opcode-8) - RequestBatchResponse (OpCode 9)(#requestbatchresponse-opcode-9) +- Enumerations(#enums) +- Events(#events) +- Requests(#requests) ## General Intro @@ -143,7 +146,7 @@ { "op": 0, "d": { - "obsWebSocketVersion": "5.0.1", + "obsWebSocketVersion": "5.1.0", "rpcVersion": 1, "authentication": { "challenge": "+IxH4CnCiqpX1rM9scsNynZzbOe4KhDeYcTNS3PDaeY=", @@ -159,7 +162,7 @@ { "op": 0, "d": { - "obsWebSocketVersion": "5.0.1", + "obsWebSocketVersion": "5.1.0", "rpcVersion": 1 } }
View file
obs-studio-28.1.2.tar.xz/plugins/obs-websocket/docs/generated/protocol.json -> obs-studio-29.0.0.tar.xz/plugins/obs-websocket/docs/generated/protocol.json
Changed
@@ -448,6 +448,83 @@ }, { + "enumType": "ObsOutputState", + "enumIdentifiers": + { + "description": "Unknown state.", + "enumIdentifier": "OBS_WEBSOCKET_OUTPUT_UNKNOWN", + "rpcVersion": 1, + "deprecated": true, + "initialVersion": "5.0.0", + "enumValue": "OBS_WEBSOCKET_OUTPUT_UNKNOWN" + }, + { + "description": "The output is starting.", + "enumIdentifier": "OBS_WEBSOCKET_OUTPUT_STARTING", + "rpcVersion": 1, + "deprecated": true, + "initialVersion": "5.0.0", + "enumValue": "OBS_WEBSOCKET_OUTPUT_STARTING" + }, + { + "description": "The input has started.", + "enumIdentifier": "OBS_WEBSOCKET_OUTPUT_STARTED", + "rpcVersion": 1, + "deprecated": true, + "initialVersion": "5.0.0", + "enumValue": "OBS_WEBSOCKET_OUTPUT_STARTED" + }, + { + "description": "The output is stopping.", + "enumIdentifier": "OBS_WEBSOCKET_OUTPUT_STOPPING", + "rpcVersion": 1, + "deprecated": true, + "initialVersion": "5.0.0", + "enumValue": "OBS_WEBSOCKET_OUTPUT_STOPPING" + }, + { + "description": "The output has stopped.", + "enumIdentifier": "OBS_WEBSOCKET_OUTPUT_STOPPED", + "rpcVersion": 1, + "deprecated": true, + "initialVersion": "5.0.0", + "enumValue": "OBS_WEBSOCKET_OUTPUT_STOPPED" + }, + { + "description": "The output has disconnected and is reconnecting.", + "enumIdentifier": "OBS_WEBSOCKET_OUTPUT_RECONNECTING", + "rpcVersion": 1, + "deprecated": true, + "initialVersion": "5.0.0", + "enumValue": "OBS_WEBSOCKET_OUTPUT_RECONNECTING" + }, + { + "description": "The output has reconnected successfully.", + "enumIdentifier": "OBS_WEBSOCKET_OUTPUT_RECONNECTED", + "rpcVersion": 1, + "deprecated": true, + "initialVersion": "5.1.0", + "enumValue": "OBS_WEBSOCKET_OUTPUT_RECONNECTED" + }, + { + "description": "The output is now paused.", + "enumIdentifier": "OBS_WEBSOCKET_OUTPUT_PAUSED", + "rpcVersion": 1, + "deprecated": true, + "initialVersion": "5.1.0", + "enumValue": "OBS_WEBSOCKET_OUTPUT_PAUSED" + }, + { + "description": "The output has been resumed (unpaused).", + "enumIdentifier": "OBS_WEBSOCKET_OUTPUT_RESUMED", + "rpcVersion": 1, + "deprecated": true, + "initialVersion": "5.0.0", + "enumValue": "OBS_WEBSOCKET_OUTPUT_RESUMED" + } + + }, + { "enumType": "ObsMediaInputAction", "enumIdentifiers": { @@ -1776,16 +1853,16 @@ "valueType": "Number", "valueDescription": "Number of milliseconds to sleep for (if `SERIAL_REALTIME` mode)", "valueRestrictions": ">= 0, <= 50000", - "valueOptional": false, - "valueOptionalBehavior": null + "valueOptional": true, + "valueOptionalBehavior": "Unknown" }, { "valueName": "sleepFrames", "valueType": "Number", "valueDescription": "Number of frames to sleep for (if `SERIAL_FRAME` mode)", "valueRestrictions": ">= 0, <= 10000", - "valueOptional": false, - "valueOptionalBehavior": null + "valueOptional": true, + "valueOptionalBehavior": "Unknown" } , "responseFields": @@ -2481,7 +2558,7 @@ }, { - "description": "Presses a button in the properties of an input.\n\nNote: Use this in cases where there is a button in the properties of an input that cannot be accessed in any other way. For example, browser sources, where there is a refresh button.", + "description": "Presses a button in the properties of an input.\n\nSome known `propertyName` values are:\n\n- `refreshnocache` - Browser source reload button\n\nNote: Use this in cases where there is a button in the properties of an input that cannot be accessed in any other way. For example, browser sources, where there is a refresh button.", "requestType": "PressInputPropertiesButton", "complexity": 4, "rpcVersion": "1", @@ -2777,7 +2854,13 @@ "initialVersion": "5.0.0", "category": "outputs", "requestFields": , - "responseFields": + "responseFields": + { + "valueName": "outputs", + "valueType": "Array<Object>", + "valueDescription": "Array of outputs" + } + }, { "description": "Gets the status of an output.", @@ -2976,7 +3059,7 @@ "valueDescription": "Whether the output is active" }, { - "valueName": "ouputPaused", + "valueName": "outputPaused", "valueType": "Boolean", "valueDescription": "Whether the output is paused" }, @@ -3096,7 +3179,7 @@ }, { - "description": "Basically GetSceneItemList, but for groups.\n\nUsing groups at all in OBS is discouraged, as they are very broken under the hood.\n\nGroups only", + "description": "Basically GetSceneItemList, but for groups.\n\nUsing groups at all in OBS is discouraged, as they are very broken under the hood. Please use nested scenes instead.\n\nGroups only", "requestType": "GetGroupSceneItemList", "complexity": 3, "rpcVersion": "1", @@ -4955,7 +5038,7 @@ { "valueName": "inputVolumeMul", "valueType": "Number", - "valueDescription": "New volume level in multimap" + "valueDescription": "New volume level multiplier" }, { "valueName": "inputVolumeDb", @@ -5639,6 +5722,23 @@ }, { + "description": "A screenshot has been saved.\n\nNote: Triggered for the screenshot feature available in `Settings -> Hotkeys -> Screenshot Output` ONLY.\nApplications using `Get/SaveSourceScreenshot` should implement a `CustomEvent` if this kind of inter-client\ncommunication is desired.", + "eventType": "ScreenshotSaved", + "eventSubscription": "Ui", + "complexity": 2, + "rpcVersion": "1", + "deprecated": false, + "initialVersion": "5.1.0", + "category": "ui", + "dataFields": + { + "valueName": "savedScreenshotPath", + "valueType": "String", + "valueDescription": "Path of the saved image file" + } + + }, + { "description": "An event has been emitted from a vendor.\n\nA vendor is a unique name registered by a third-party plugin or script, which allows for custom requests and events to be added to obs-websocket.\nIf a plugin or script implements vendor requests or events, documentation is expected to be provided with them.", "eventType": "VendorEvent", "eventSubscription": "Vendors", @@ -5664,6 +5764,23 @@ "valueDescription": "Vendor-provided event data. {} if event does not provide any data" } + }, + { + "description": "Custom event emitted by `BroadcastCustomEvent`.", + "eventType": "CustomEvent", + "eventSubscription": "General", + "complexity": 1, + "rpcVersion": "1", + "deprecated": false, + "initialVersion": "5.0.0", + "category": "general", + "dataFields": + { + "valueName": "eventData", + "valueType": "Object", + "valueDescription": "Custom event data" + } + } } \ No newline at end of file
View file
obs-studio-28.1.2.tar.xz/plugins/obs-websocket/docs/generated/protocol.md -> obs-studio-29.0.0.tar.xz/plugins/obs-websocket/docs/generated/protocol.md
Changed
@@ -21,6 +21,9 @@ - RequestResponse (OpCode 7)(#requestresponse-opcode-7) - RequestBatch (OpCode 8)(#requestbatch-opcode-8) - RequestBatchResponse (OpCode 9)(#requestbatchresponse-opcode-9) +- Enumerations(#enums) +- Events(#events) +- Requests(#requests) ## General Intro @@ -512,6 +515,24 @@ - EventSubscription::InputActiveStateChanged(#eventsubscriptioninputactivestatechanged) - EventSubscription::InputShowStateChanged(#eventsubscriptioninputshowstatechanged) - EventSubscription::SceneItemTransformChanged(#eventsubscriptionsceneitemtransformchanged) +- ObsMediaInputAction(#obsmediainputaction) + - ObsMediaInputAction::OBS_WEBSOCKET_MEDIA_INPUT_ACTION_NONE(#obsmediainputactionobs_websocket_media_input_action_none) + - ObsMediaInputAction::OBS_WEBSOCKET_MEDIA_INPUT_ACTION_PLAY(#obsmediainputactionobs_websocket_media_input_action_play) + - ObsMediaInputAction::OBS_WEBSOCKET_MEDIA_INPUT_ACTION_PAUSE(#obsmediainputactionobs_websocket_media_input_action_pause) + - ObsMediaInputAction::OBS_WEBSOCKET_MEDIA_INPUT_ACTION_STOP(#obsmediainputactionobs_websocket_media_input_action_stop) + - ObsMediaInputAction::OBS_WEBSOCKET_MEDIA_INPUT_ACTION_RESTART(#obsmediainputactionobs_websocket_media_input_action_restart) + - ObsMediaInputAction::OBS_WEBSOCKET_MEDIA_INPUT_ACTION_NEXT(#obsmediainputactionobs_websocket_media_input_action_next) + - ObsMediaInputAction::OBS_WEBSOCKET_MEDIA_INPUT_ACTION_PREVIOUS(#obsmediainputactionobs_websocket_media_input_action_previous) +- ObsOutputState(#obsoutputstate) + - ObsOutputState::OBS_WEBSOCKET_OUTPUT_UNKNOWN(#obsoutputstateobs_websocket_output_unknown) + - ObsOutputState::OBS_WEBSOCKET_OUTPUT_STARTING(#obsoutputstateobs_websocket_output_starting) + - ObsOutputState::OBS_WEBSOCKET_OUTPUT_STARTED(#obsoutputstateobs_websocket_output_started) + - ObsOutputState::OBS_WEBSOCKET_OUTPUT_STOPPING(#obsoutputstateobs_websocket_output_stopping) + - ObsOutputState::OBS_WEBSOCKET_OUTPUT_STOPPED(#obsoutputstateobs_websocket_output_stopped) + - ObsOutputState::OBS_WEBSOCKET_OUTPUT_RECONNECTING(#obsoutputstateobs_websocket_output_reconnecting) + - ObsOutputState::OBS_WEBSOCKET_OUTPUT_RECONNECTED(#obsoutputstateobs_websocket_output_reconnected) + - ObsOutputState::OBS_WEBSOCKET_OUTPUT_PAUSED(#obsoutputstateobs_websocket_output_paused) + - ObsOutputState::OBS_WEBSOCKET_OUTPUT_RESUMED(#obsoutputstateobs_websocket_output_resumed) ## WebSocketOpCode @@ -1294,6 +1315,182 @@ - Latest Supported RPC Version: `1` - Added in v5.0.0 +## ObsMediaInputAction + +### ObsMediaInputAction::OBS_WEBSOCKET_MEDIA_INPUT_ACTION_NONE + +No action. + +- Identifier Value: `OBS_WEBSOCKET_MEDIA_INPUT_ACTION_NONE` +- Latest Supported RPC Version: `1` +- **⚠️ Deprecated. ⚠️** +- Added in v5.0.0 + +--- + +### ObsMediaInputAction::OBS_WEBSOCKET_MEDIA_INPUT_ACTION_PLAY + +Play the media input. + +- Identifier Value: `OBS_WEBSOCKET_MEDIA_INPUT_ACTION_PLAY` +- Latest Supported RPC Version: `1` +- **⚠️ Deprecated. ⚠️** +- Added in v5.0.0 + +--- + +### ObsMediaInputAction::OBS_WEBSOCKET_MEDIA_INPUT_ACTION_PAUSE + +Pause the media input. + +- Identifier Value: `OBS_WEBSOCKET_MEDIA_INPUT_ACTION_PAUSE` +- Latest Supported RPC Version: `1` +- **⚠️ Deprecated. ⚠️** +- Added in v5.0.0 + +--- + +### ObsMediaInputAction::OBS_WEBSOCKET_MEDIA_INPUT_ACTION_STOP + +Stop the media input. + +- Identifier Value: `OBS_WEBSOCKET_MEDIA_INPUT_ACTION_STOP` +- Latest Supported RPC Version: `1` +- **⚠️ Deprecated. ⚠️** +- Added in v5.0.0 + +--- + +### ObsMediaInputAction::OBS_WEBSOCKET_MEDIA_INPUT_ACTION_RESTART + +Restart the media input. + +- Identifier Value: `OBS_WEBSOCKET_MEDIA_INPUT_ACTION_RESTART` +- Latest Supported RPC Version: `1` +- **⚠️ Deprecated. ⚠️** +- Added in v5.0.0 + +--- + +### ObsMediaInputAction::OBS_WEBSOCKET_MEDIA_INPUT_ACTION_NEXT + +Go to the next playlist item. + +- Identifier Value: `OBS_WEBSOCKET_MEDIA_INPUT_ACTION_NEXT` +- Latest Supported RPC Version: `1` +- **⚠️ Deprecated. ⚠️** +- Added in v5.0.0 + +--- + +### ObsMediaInputAction::OBS_WEBSOCKET_MEDIA_INPUT_ACTION_PREVIOUS + +Go to the previous playlist item. + +- Identifier Value: `OBS_WEBSOCKET_MEDIA_INPUT_ACTION_PREVIOUS` +- Latest Supported RPC Version: `1` +- **⚠️ Deprecated. ⚠️** +- Added in v5.0.0 + +## ObsOutputState + +### ObsOutputState::OBS_WEBSOCKET_OUTPUT_UNKNOWN + +Unknown state. + +- Identifier Value: `OBS_WEBSOCKET_OUTPUT_UNKNOWN` +- Latest Supported RPC Version: `1` +- **⚠️ Deprecated. ⚠️** +- Added in v5.0.0 + +--- + +### ObsOutputState::OBS_WEBSOCKET_OUTPUT_STARTING + +The output is starting. + +- Identifier Value: `OBS_WEBSOCKET_OUTPUT_STARTING` +- Latest Supported RPC Version: `1` +- **⚠️ Deprecated. ⚠️** +- Added in v5.0.0 + +--- + +### ObsOutputState::OBS_WEBSOCKET_OUTPUT_STARTED + +The input has started. + +- Identifier Value: `OBS_WEBSOCKET_OUTPUT_STARTED` +- Latest Supported RPC Version: `1` +- **⚠️ Deprecated. ⚠️** +- Added in v5.0.0 + +--- + +### ObsOutputState::OBS_WEBSOCKET_OUTPUT_STOPPING + +The output is stopping. + +- Identifier Value: `OBS_WEBSOCKET_OUTPUT_STOPPING` +- Latest Supported RPC Version: `1` +- **⚠️ Deprecated. ⚠️** +- Added in v5.0.0 + +--- + +### ObsOutputState::OBS_WEBSOCKET_OUTPUT_STOPPED + +The output has stopped. + +- Identifier Value: `OBS_WEBSOCKET_OUTPUT_STOPPED` +- Latest Supported RPC Version: `1` +- **⚠️ Deprecated. ⚠️** +- Added in v5.0.0 + +--- + +### ObsOutputState::OBS_WEBSOCKET_OUTPUT_RECONNECTING + +The output has disconnected and is reconnecting. + +- Identifier Value: `OBS_WEBSOCKET_OUTPUT_RECONNECTING` +- Latest Supported RPC Version: `1` +- **⚠️ Deprecated. ⚠️** +- Added in v5.0.0 + +--- + +### ObsOutputState::OBS_WEBSOCKET_OUTPUT_RECONNECTED + +The output has reconnected successfully. + +- Identifier Value: `OBS_WEBSOCKET_OUTPUT_RECONNECTED` +- Latest Supported RPC Version: `1` +- **⚠️ Deprecated. ⚠️** +- Added in v5.1.0 + +--- + +### ObsOutputState::OBS_WEBSOCKET_OUTPUT_PAUSED + +The output is now paused. + +- Identifier Value: `OBS_WEBSOCKET_OUTPUT_PAUSED` +- Latest Supported RPC Version: `1` +- **⚠️ Deprecated. ⚠️** +- Added in v5.1.0 + +--- + +### ObsOutputState::OBS_WEBSOCKET_OUTPUT_RESUMED + +The output has been resumed (unpaused). + +- Identifier Value: `OBS_WEBSOCKET_OUTPUT_RESUMED` +- Latest Supported RPC Version: `1` +- **⚠️ Deprecated. ⚠️** +- Added in v5.0.0 + # Events ## Events Table of Contents @@ -1301,6 +1498,7 @@ - General Events(#general-events) - ExitStarted(#exitstarted) - VendorEvent(#vendorevent) + - CustomEvent(#customevent) - Config Events(#config-events) - CurrentSceneCollectionChanging(#currentscenecollectionchanging) - CurrentSceneCollectionChanged(#currentscenecollectionchanged) @@ -1360,6 +1558,7 @@ - MediaInputActionTriggered(#mediainputactiontriggered) - Ui Events(#ui-events) - StudioModeStateChanged(#studiomodestatechanged) + - ScreenshotSaved(#screenshotsaved) ## General Events @@ -1392,6 +1591,22 @@ | eventType | String | Vendor-provided event typedef | | eventData | Object | Vendor-provided event data. {} if event does not provide any data | +--- + +### CustomEvent + +Custom event emitted by `BroadcastCustomEvent`. + +- Complexity Rating: `1/5` +- Latest Supported RPC Version: `1` +- Added in v5.0.0 + +**Data Fields:** + +| Name | Type | Description | +| ---- | :---: | ----------- | +| eventData | Object | Custom event data | + ## Config Events ### CurrentSceneCollectionChanging @@ -1717,7 +1932,7 @@ | Name | Type | Description | | ---- | :---: | ----------- | | inputName | String | Name of the input | -| inputVolumeMul | Number | New volume level in multimap | +| inputVolumeMul | Number | New volume level multiplier | | inputVolumeDb | Number | New volume level in dB | --- @@ -2265,6 +2480,26 @@ | ---- | :---: | ----------- | | studioModeEnabled | Boolean | True == Enabled, False == Disabled | +--- + +### ScreenshotSaved + +A screenshot has been saved. + +Note: Triggered for the screenshot feature available in `Settings -> Hotkeys -> Screenshot Output` ONLY. +Applications using `Get/SaveSourceScreenshot` should implement a `CustomEvent` if this kind of inter-client +communication is desired. + +- Complexity Rating: `2/5` +- Latest Supported RPC Version: `1` +- Added in v5.1.0 + +**Data Fields:** + +| Name | Type | Description | +| ---- | :---: | ----------- | +| savedScreenshotPath | String | Path of the saved image file | + # Requests ## Requests Table of Contents @@ -2580,8 +2815,8 @@ | Name | Type | Description | Value Restrictions | ?Default Behavior | | ---- | :---: | ----------- | :----------------: | ----------------- | -| sleepMillis | Number | Number of milliseconds to sleep for (if `SERIAL_REALTIME` mode) | >= 0, <= 50000 | N/A | -| sleepFrames | Number | Number of frames to sleep for (if `SERIAL_FRAME` mode) | >= 0, <= 10000 | N/A | +| ?sleepMillis | Number | Number of milliseconds to sleep for (if `SERIAL_REALTIME` mode) | >= 0, <= 50000 | Unknown | +| ?sleepFrames | Number | Number of frames to sleep for (if `SERIAL_FRAME` mode) | >= 0, <= 10000 | Unknown | ## Config Requests @@ -3652,6 +3887,10 @@ Presses a button in the properties of an input. +Some known `propertyName` values are: + +- `refreshnocache` - Browser source reload button + Note: Use this in cases where there is a button in the properties of an input that cannot be accessed in any other way. For example, browser sources, where there is a refresh button. - Complexity Rating: `4/5` @@ -4029,7 +4268,7 @@ Basically GetSceneItemList, but for groups. -Using groups at all in OBS is discouraged, as they are very broken under the hood. +Using groups at all in OBS is discouraged, as they are very broken under the hood. Please use nested scenes instead. Groups only @@ -4521,6 +4760,12 @@ - Latest Supported RPC Version: `1` - Added in v5.0.0 +**Response Fields:** + +| Name | Type | Description | +| ---- | :---: | ----------- | +| outputs | Array<Object> | Array of outputs | + --- ### GetOutputStatus @@ -4733,7 +4978,7 @@ | Name | Type | Description | | ---- | :---: | ----------- | | outputActive | Boolean | Whether the output is active | -| ouputPaused | Boolean | Whether the output is paused | +| outputPaused | Boolean | Whether the output is paused | | outputTimecode | String | Current formatted timecode string for the output | | outputDuration | Number | Current duration in milliseconds for the output | | outputBytes | Number | Number of bytes sent by the output |
View file
obs-studio-28.1.2.tar.xz/plugins/obs-websocket/src/eventhandler/EventHandler.cpp -> obs-studio-29.0.0.tar.xz/plugins/obs-websocket/src/eventhandler/EventHandler.cpp
Changed
@@ -267,97 +267,10 @@ switch (event) { // General case OBS_FRONTEND_EVENT_FINISHED_LOADING: - blog_debug( - "EventHandler::OnFrontendEvent OBS has finished loading. Connecting final handlers and enabling events..."); - - // Connect source signals and enable events only after OBS has fully loaded (to reduce extra logging). - eventHandler->_obsLoaded.store(true); - - // In the case that plugins become hotloadable, this will have to go back into `EventHandler::EventHandler()` - // Enumerate inputs and connect each one - { - auto enumInputs = (void *param, obs_source_t *source) { - auto eventHandler = static_cast<EventHandler *>(param); - eventHandler->ConnectSourceSignals(source); - return true; - }; - obs_enum_sources(enumInputs, private_data); - } - - // Enumerate scenes and connect each one - { - auto enumScenes = (void *param, obs_source_t *source) { - auto eventHandler = static_cast<EventHandler *>(param); - eventHandler->ConnectSourceSignals(source); - return true; - }; - obs_enum_scenes(enumScenes, private_data); - } - - // Enumerate all scene transitions and connect each one - { - obs_frontend_source_list transitions = {}; - obs_frontend_get_transitions(&transitions); - for (size_t i = 0; i < transitions.sources.num; i++) { - obs_source_t *transition = transitions.sources.arrayi; - eventHandler->ConnectSourceSignals(transition); - } - obs_frontend_source_list_free(&transitions); - } - - blog_debug("EventHandler::OnFrontendEvent Finished."); - - if (eventHandler->_obsLoadedCallback) - eventHandler->_obsLoadedCallback(); - + eventHandler->FrontendFinishedLoadingMultiHandler(); break; case OBS_FRONTEND_EVENT_EXIT: - eventHandler->HandleExitStarted(); - - blog_debug("EventHandler::OnFrontendEvent OBS is unloading. Disabling events..."); - // Disconnect source signals and disable events when OBS starts unloading (to reduce extra logging). - eventHandler->_obsLoaded.store(false); - - // In the case that plugins become hotloadable, this will have to go back into `EventHandler::~EventHandler()` - // Enumerate inputs and disconnect each one - { - auto enumInputs = (void *param, obs_source_t *source) { - auto eventHandler = static_cast<EventHandler *>(param); - eventHandler->DisconnectSourceSignals(source); - return true; - }; - obs_enum_sources(enumInputs, private_data); - } - - // Enumerate scenes and disconnect each one - { - auto enumScenes = (void *param, obs_source_t *source) { - auto eventHandler = static_cast<EventHandler *>(param); - eventHandler->DisconnectSourceSignals(source); - return true; - }; - obs_enum_scenes(enumScenes, private_data); - } - - // Enumerate all scene transitions and disconnect each one - { - obs_frontend_source_list transitions = {}; - obs_frontend_get_transitions(&transitions); - for (size_t i = 0; i < transitions.sources.num; i++) { - obs_source_t *transition = transitions.sources.arrayi; - eventHandler->DisconnectSourceSignals(transition); - } - obs_frontend_source_list_free(&transitions); - } - - blog_debug("EventHandler::OnFrontendEvent Finished."); - - break; - case OBS_FRONTEND_EVENT_STUDIO_MODE_ENABLED: - eventHandler->HandleStudioModeStateChanged(true); - break; - case OBS_FRONTEND_EVENT_STUDIO_MODE_DISABLED: - eventHandler->HandleStudioModeStateChanged(false); + eventHandler->FrontendExitMultiHandler(); break; // Config @@ -427,12 +340,31 @@ // Outputs case OBS_FRONTEND_EVENT_STREAMING_STARTING: eventHandler->HandleStreamStateChanged(OBS_WEBSOCKET_OUTPUT_STARTING); + { + // Connect signals for stream output reconnects (hacky) + OBSOutputAutoRelease streamOutput = obs_frontend_get_streaming_output(); + if (streamOutput) { + signal_handler_t *sh = obs_output_get_signal_handler(streamOutput); + signal_handler_connect(sh, "reconnect", StreamOutputReconnectHandler, private_data); + signal_handler_connect(sh, "reconnect_success", StreamOutputReconnectSuccessHandler, private_data); + } + } break; case OBS_FRONTEND_EVENT_STREAMING_STARTED: eventHandler->HandleStreamStateChanged(OBS_WEBSOCKET_OUTPUT_STARTED); break; case OBS_FRONTEND_EVENT_STREAMING_STOPPING: eventHandler->HandleStreamStateChanged(OBS_WEBSOCKET_OUTPUT_STOPPING); + { + // Disconnect signals for stream output reconnects + OBSOutputAutoRelease streamOutput = obs_frontend_get_streaming_output(); + if (streamOutput) { + signal_handler_t *sh = obs_output_get_signal_handler(streamOutput); + signal_handler_disconnect(sh, "reconnect", StreamOutputReconnectHandler, private_data); + signal_handler_disconnect(sh, "reconnect_success", StreamOutputReconnectSuccessHandler, + private_data); + } + } break; case OBS_FRONTEND_EVENT_STREAMING_STOPPED: eventHandler->HandleStreamStateChanged(OBS_WEBSOCKET_OUTPUT_STOPPED); @@ -477,11 +409,112 @@ eventHandler->HandleReplayBufferSaved(); break; + // Ui + case OBS_FRONTEND_EVENT_STUDIO_MODE_ENABLED: + eventHandler->HandleStudioModeStateChanged(true); + break; + case OBS_FRONTEND_EVENT_STUDIO_MODE_DISABLED: + eventHandler->HandleStudioModeStateChanged(false); + break; + case OBS_FRONTEND_EVENT_SCREENSHOT_TAKEN: + eventHandler->HandleScreenshotSaved(); + break; + default: break; } } +void EventHandler::FrontendFinishedLoadingMultiHandler() +{ + blog_debug( + "EventHandler::FrontendFinishedLoadingMultiHandler OBS has finished loading. Connecting final handlers and enabling events..."); + + // Connect source signals and enable events only after OBS has fully loaded (to reduce extra logging). + _obsLoaded.store(true); + + // In the case that plugins become hotloadable, this will have to go back into `EventHandler::EventHandler()` + // Enumerate inputs and connect each one + { + auto enumInputs = (void *param, obs_source_t *source) { + auto eventHandler = static_cast<EventHandler *>(param); + eventHandler->ConnectSourceSignals(source); + return true; + }; + obs_enum_sources(enumInputs, this); + } + + // Enumerate scenes and connect each one + { + auto enumScenes = (void *param, obs_source_t *source) { + auto eventHandler = static_cast<EventHandler *>(param); + eventHandler->ConnectSourceSignals(source); + return true; + }; + obs_enum_scenes(enumScenes, this); + } + + // Enumerate all scene transitions and connect each one + { + obs_frontend_source_list transitions = {}; + obs_frontend_get_transitions(&transitions); + for (size_t i = 0; i < transitions.sources.num; i++) { + obs_source_t *transition = transitions.sources.arrayi; + ConnectSourceSignals(transition); + } + obs_frontend_source_list_free(&transitions); + } + + blog_debug("EventHandler::FrontendFinishedLoadingMultiHandler Finished."); + + if (_obsLoadedCallback) + _obsLoadedCallback(); +} + +void EventHandler::FrontendExitMultiHandler() +{ + HandleExitStarted(); + + blog_debug("EventHandler::FrontendExitMultiHandler OBS is unloading. Disabling events..."); + + // Disconnect source signals and disable events when OBS starts unloading (to reduce extra logging). + _obsLoaded.store(false); + + // In the case that plugins become hotloadable, this will have to go back into `EventHandler::~EventHandler()` + // Enumerate inputs and disconnect each one + { + auto enumInputs = (void *param, obs_source_t *source) { + auto eventHandler = static_cast<EventHandler *>(param); + eventHandler->DisconnectSourceSignals(source); + return true; + }; + obs_enum_sources(enumInputs, this); + } + + // Enumerate scenes and disconnect each one + { + auto enumScenes = (void *param, obs_source_t *source) { + auto eventHandler = static_cast<EventHandler *>(param); + eventHandler->DisconnectSourceSignals(source); + return true; + }; + obs_enum_scenes(enumScenes, this); + } + + // Enumerate all scene transitions and disconnect each one + { + obs_frontend_source_list transitions = {}; + obs_frontend_get_transitions(&transitions); + for (size_t i = 0; i < transitions.sources.num; i++) { + obs_source_t *transition = transitions.sources.arrayi; + DisconnectSourceSignals(transition); + } + obs_frontend_source_list_free(&transitions); + } + + blog_debug("EventHandler::FrontendExitMultiHandler Finished."); +} + // Only called for creation of a public source void EventHandler::SourceCreatedMultiHandler(void *param, calldata_t *data) { @@ -597,3 +630,17 @@ break; } } + +void EventHandler::StreamOutputReconnectHandler(void *param, calldata_t *) +{ + auto eventHandler = static_cast<EventHandler *>(param); + + eventHandler->HandleStreamStateChanged(OBS_WEBSOCKET_OUTPUT_RECONNECTING); +} + +void EventHandler::StreamOutputReconnectSuccessHandler(void *param, calldata_t *) +{ + auto eventHandler = static_cast<EventHandler *>(param); + + eventHandler->HandleStreamStateChanged(OBS_WEBSOCKET_OUTPUT_RECONNECTED); +}
View file
obs-studio-28.1.2.tar.xz/plugins/obs-websocket/src/eventhandler/EventHandler.h -> obs-studio-29.0.0.tar.xz/plugins/obs-websocket/src/eventhandler/EventHandler.h
Changed
@@ -61,6 +61,8 @@ // Signal handler: frontend static void OnFrontendEvent(enum obs_frontend_event event, void *private_data); + void FrontendFinishedLoadingMultiHandler(); + void FrontendExitMultiHandler(); // Signal handler: libobs static void SourceCreatedMultiHandler(void *param, calldata_t *data); @@ -76,9 +78,12 @@ static void SourceMediaNextMultiHandler(void *param, calldata_t *data); static void SourceMediaPreviousMultiHandler(void *param, calldata_t *data); + // Signal handler: output + static void StreamOutputReconnectHandler(void *param, calldata_t *data); + static void StreamOutputReconnectSuccessHandler(void *param, calldata_t *data); + // General void HandleExitStarted(); - void HandleStudioModeStateChanged(bool enabled); // Config void HandleCurrentSceneCollectionChanging(); @@ -170,4 +175,8 @@ static void HandleMediaInputPlaybackEnded(void *param, calldata_t *data); // Direct callback void HandleMediaInputActionTriggered(obs_source_t *source, ObsMediaInputAction action); + + // Ui + void HandleStudioModeStateChanged(bool enabled); + void HandleScreenshotSaved(); };
View file
obs-studio-28.1.2.tar.xz/plugins/obs-websocket/src/eventhandler/EventHandler_Inputs.cpp -> obs-studio-29.0.0.tar.xz/plugins/obs-websocket/src/eventhandler/EventHandler_Inputs.cpp
Changed
@@ -200,7 +200,7 @@ * An input's volume level has changed. * * @dataField inputName | String | Name of the input - * @dataField inputVolumeMul | Number | New volume level in multimap + * @dataField inputVolumeMul | Number | New volume level multiplier * @dataField inputVolumeDb | Number | New volume level in dB * * @eventType InputVolumeChanged
View file
obs-studio-28.1.2.tar.xz/plugins/obs-websocket/src/eventhandler/EventHandler_Outputs.cpp -> obs-studio-29.0.0.tar.xz/plugins/obs-websocket/src/eventhandler/EventHandler_Outputs.cpp
Changed
@@ -24,10 +24,12 @@ switch (state) { case OBS_WEBSOCKET_OUTPUT_STARTED: case OBS_WEBSOCKET_OUTPUT_RESUMED: + case OBS_WEBSOCKET_OUTPUT_RECONNECTED: return true; case OBS_WEBSOCKET_OUTPUT_STARTING: case OBS_WEBSOCKET_OUTPUT_STOPPING: case OBS_WEBSOCKET_OUTPUT_STOPPED: + case OBS_WEBSOCKET_OUTPUT_RECONNECTING: case OBS_WEBSOCKET_OUTPUT_PAUSED: return false; default:
View file
obs-studio-28.1.2.tar.xz/plugins/obs-websocket/src/eventhandler/EventHandler_Ui.cpp -> obs-studio-29.0.0.tar.xz/plugins/obs-websocket/src/eventhandler/EventHandler_Ui.cpp
Changed
@@ -38,3 +38,27 @@ eventData"studioModeEnabled" = enabled; BroadcastEvent(EventSubscription::Ui, "StudioModeStateChanged", eventData); } + +/** + * A screenshot has been saved. + * + * Note: Triggered for the screenshot feature available in `Settings -> Hotkeys -> Screenshot Output` ONLY. + * Applications using `Get/SaveSourceScreenshot` should implement a `CustomEvent` if this kind of inter-client + * communication is desired. + * + * @dataField savedScreenshotPath | String | Path of the saved image file + * + * @eventType ScreenshotSaved + * @eventSubscription Ui + * @complexity 2 + * @rpcVersion -1 + * @initialVersion 5.1.0 + * @api events + * @category ui + */ +void EventHandler::HandleScreenshotSaved() +{ + json eventData; + eventData"savedScreenshotPath" = Utils::Obs::StringHelper::GetLastScreenshotFileName(); + BroadcastEvent(EventSubscription::Ui, "ScreenshotSaved", eventData); +}
View file
obs-studio-28.1.2.tar.xz/plugins/obs-websocket/src/forms/ConnectInfo.cpp -> obs-studio-29.0.0.tar.xz/plugins/obs-websocket/src/forms/ConnectInfo.cpp
Changed
@@ -105,7 +105,7 @@ void ConnectInfo::DrawQr(QString qrText) { - QPixmap map(230, 230); + QPixmap map(236, 236); map.fill(Qt::white); QPainter painter(&map);
View file
obs-studio-28.1.2.tar.xz/plugins/obs-websocket/src/forms/ConnectInfo.ui -> obs-studio-29.0.0.tar.xz/plugins/obs-websocket/src/forms/ConnectInfo.ui
Changed
@@ -7,7 +7,7 @@ <x>0</x> <y>0</y> <width>451</width> - <height>412</height> + <height>432</height> </rect> </property> <property name="minimumSize"> @@ -19,7 +19,7 @@ <property name="maximumSize"> <size> <width>451</width> - <height>412</height> + <height>432</height> </size> </property> <property name="windowTitle"> @@ -31,12 +31,21 @@ <x>10</x> <y>10</y> <width>431</width> - <height>101</height> + <height>121</height> </rect> </property> <layout class="QFormLayout" name="formLayout"> + <property name="formAlignment"> + <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set> + </property> <item row="0" column="0"> <widget class="QLabel" name="serverIpLabel"> + <property name="maximumSize"> + <size> + <width>200</width> + <height>16777215</height> + </size> + </property> <property name="text"> <string>OBSWebSocket.ConnectInfo.ServerIp</string> </property> @@ -46,6 +55,12 @@ <layout class="QHBoxLayout" name="horizontalLayout"> <item> <widget class="QLineEdit" name="serverIpLineEdit"> + <property name="focusPolicy"> + <enum>Qt::NoFocus</enum> + </property> + <property name="alignment"> + <set>Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft</set> + </property> <property name="readOnly"> <bool>true</bool> </property> @@ -53,6 +68,12 @@ </item> <item> <widget class="QPushButton" name="copyServerIpButton"> + <property name="maximumSize"> + <size> + <width>75</width> + <height>16777215</height> + </size> + </property> <property name="text"> <string>OBSWebSocket.ConnectInfo.CopyText</string> </property> @@ -62,6 +83,12 @@ </item> <item row="1" column="0"> <widget class="QLabel" name="serverPortLabel"> + <property name="maximumSize"> + <size> + <width>200</width> + <height>16777215</height> + </size> + </property> <property name="text"> <string>OBSWebSocket.ConnectInfo.ServerPort</string> </property> @@ -71,6 +98,12 @@ <layout class="QHBoxLayout" name="horizontalLayout_2"> <item> <widget class="QLineEdit" name="serverPortLineEdit"> + <property name="focusPolicy"> + <enum>Qt::NoFocus</enum> + </property> + <property name="alignment"> + <set>Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft</set> + </property> <property name="readOnly"> <bool>true</bool> </property> @@ -78,6 +111,12 @@ </item> <item> <widget class="QPushButton" name="copyServerPortButton"> + <property name="maximumSize"> + <size> + <width>75</width> + <height>16777215</height> + </size> + </property> <property name="text"> <string>OBSWebSocket.ConnectInfo.CopyText</string> </property> @@ -87,6 +126,12 @@ </item> <item row="2" column="0"> <widget class="QLabel" name="serverPasswordLabel"> + <property name="maximumSize"> + <size> + <width>200</width> + <height>16777215</height> + </size> + </property> <property name="text"> <string>OBSWebSocket.ConnectInfo.ServerPassword</string> </property> @@ -96,9 +141,15 @@ <layout class="QHBoxLayout" name="horizontalLayout_3"> <item> <widget class="QLineEdit" name="serverPasswordLineEdit"> + <property name="focusPolicy"> + <enum>Qt::NoFocus</enum> + </property> <property name="text"> <string>OBSWebSocket.ConnectInfo.ServerPasswordPlaceholderText</string> </property> + <property name="alignment"> + <set>Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft</set> + </property> <property name="readOnly"> <bool>true</bool> </property> @@ -106,6 +157,12 @@ </item> <item> <widget class="QPushButton" name="copyServerPasswordButton"> + <property name="maximumSize"> + <size> + <width>75</width> + <height>16777215</height> + </size> + </property> <property name="text"> <string>OBSWebSocket.ConnectInfo.CopyText</string> </property> @@ -119,7 +176,7 @@ <property name="geometry"> <rect> <x>10</x> - <y>120</y> + <y>140</y> <width>431</width> <height>281</height> </rect> @@ -131,9 +188,9 @@ <property name="geometry"> <rect> <x>100</x> - <y>40</y> - <width>230</width> - <height>230</height> + <y>30</y> + <width>236</width> + <height>236</height> </rect> </property> <property name="text">
View file
obs-studio-28.1.2.tar.xz/plugins/obs-websocket/src/forms/SettingsDialog.ui -> obs-studio-29.0.0.tar.xz/plugins/obs-websocket/src/forms/SettingsDialog.ui
Changed
@@ -80,7 +80,7 @@ <item row="3" column="1"> <layout class="QHBoxLayout" name="horizontalLayout_2"> <property name="spacing"> - <number>0</number> + <number>2</number> </property> <item> <widget class="QCheckBox" name="enableDebugLoggingCheckBox"> @@ -97,6 +97,12 @@ <property name="toolTip"> <string>OBSWebSocket.Settings.DebugEnableHoverText</string> </property> + <property name="scaledContents"> + <bool>true</bool> + </property> + <property name="alignment"> + <set>Qt::AlignCenter</set> + </property> </widget> </item> <item>
View file
obs-studio-28.1.2.tar.xz/plugins/obs-websocket/src/requesthandler/RequestHandler_General.cpp -> obs-studio-29.0.0.tar.xz/plugins/obs-websocket/src/requesthandler/RequestHandler_General.cpp
Changed
@@ -103,6 +103,20 @@ } /** + * Custom event emitted by `BroadcastCustomEvent`. + * + * @dataField eventData | Object | Custom event data + * + * @eventType CustomEvent + * @eventSubscription General + * @complexity 1 + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @category general + * @api events + */ + +/** * Broadcasts a `CustomEvent` to all WebSocket clients. Receivers are clients which are identified and subscribed. * * @requestField eventData | Object | Data payload to emit to all receivers @@ -311,8 +325,8 @@ /** * Sleeps for a time duration or number of frames. Only available in request batches with types `SERIAL_REALTIME` or `SERIAL_FRAME`. * - * @requestField sleepMillis | Number | Number of milliseconds to sleep for (if `SERIAL_REALTIME` mode) | >= 0, <= 50000 - * @requestField sleepFrames | Number | Number of frames to sleep for (if `SERIAL_FRAME` mode) | >= 0, <= 10000 + * @requestField ?sleepMillis | Number | Number of milliseconds to sleep for (if `SERIAL_REALTIME` mode) | >= 0, <= 50000 + * @requestField ?sleepFrames | Number | Number of frames to sleep for (if `SERIAL_FRAME` mode) | >= 0, <= 10000 * * @requestType Sleep * @complexity 2
View file
obs-studio-28.1.2.tar.xz/plugins/obs-websocket/src/requesthandler/RequestHandler_Inputs.cpp -> obs-studio-29.0.0.tar.xz/plugins/obs-websocket/src/requesthandler/RequestHandler_Inputs.cpp
Changed
@@ -889,6 +889,10 @@ /** * Presses a button in the properties of an input. * + * Some known `propertyName` values are: + * + * - `refreshnocache` - Browser source reload button + * * Note: Use this in cases where there is a button in the properties of an input that cannot be accessed in any other way. For example, browser sources, where there is a refresh button. * * @requestField inputName | String | Name of the input
View file
obs-studio-28.1.2.tar.xz/plugins/obs-websocket/src/requesthandler/RequestHandler_Outputs.cpp -> obs-studio-29.0.0.tar.xz/plugins/obs-websocket/src/requesthandler/RequestHandler_Outputs.cpp
Changed
@@ -278,6 +278,8 @@ /** * Gets the list of available outputs. + * + * @responseField outputs | Array<Object> | Array of outputs * * @requestType GetOutputList * @complexity 4
View file
obs-studio-28.1.2.tar.xz/plugins/obs-websocket/src/requesthandler/RequestHandler_Record.cpp -> obs-studio-29.0.0.tar.xz/plugins/obs-websocket/src/requesthandler/RequestHandler_Record.cpp
Changed
@@ -23,7 +23,7 @@ * Gets the status of the record output. * * @responseField outputActive | Boolean | Whether the output is active - * @responseField ouputPaused | Boolean | Whether the output is paused + * @responseField outputPaused | Boolean | Whether the output is paused * @responseField outputTimecode | String | Current formatted timecode string for the output * @responseField outputDuration | Number | Current duration in milliseconds for the output * @responseField outputBytes | Number | Number of bytes sent by the output
View file
obs-studio-28.1.2.tar.xz/plugins/obs-websocket/src/requesthandler/RequestHandler_SceneItems.cpp -> obs-studio-29.0.0.tar.xz/plugins/obs-websocket/src/requesthandler/RequestHandler_SceneItems.cpp
Changed
@@ -52,7 +52,7 @@ /** * Basically GetSceneItemList, but for groups. * - * Using groups at all in OBS is discouraged, as they are very broken under the hood. + * Using groups at all in OBS is discouraged, as they are very broken under the hood. Please use nested scenes instead. * * Groups only *
View file
obs-studio-28.1.2.tar.xz/plugins/obs-websocket/src/utils/Obs.h -> obs-studio-29.0.0.tar.xz/plugins/obs-websocket/src/utils/Obs.h
Changed
@@ -67,22 +67,105 @@ } enum ObsOutputState { + /** + * Unknown state. + * + * @enumIdentifier OBS_WEBSOCKET_OUTPUT_UNKNOWN + * @enumType ObsOutputState + * @rpcVersion 1 + * @initialVersion 5.0.0 + * @api enums + */ OBS_WEBSOCKET_OUTPUT_UNKNOWN, + /** + * The output is starting. + * + * @enumIdentifier OBS_WEBSOCKET_OUTPUT_STARTING + * @enumType ObsOutputState + * @rpcVersion 1 + * @initialVersion 5.0.0 + * @api enums + */ OBS_WEBSOCKET_OUTPUT_STARTING, + /** + * The input has started. + * + * @enumIdentifier OBS_WEBSOCKET_OUTPUT_STARTED + * @enumType ObsOutputState + * @rpcVersion 1 + * @initialVersion 5.0.0 + * @api enums + */ OBS_WEBSOCKET_OUTPUT_STARTED, + /** + * The output is stopping. + * + * @enumIdentifier OBS_WEBSOCKET_OUTPUT_STOPPING + * @enumType ObsOutputState + * @rpcVersion 1 + * @initialVersion 5.0.0 + * @api enums + */ OBS_WEBSOCKET_OUTPUT_STOPPING, + /** + * The output has stopped. + * + * @enumIdentifier OBS_WEBSOCKET_OUTPUT_STOPPED + * @enumType ObsOutputState + * @rpcVersion 1 + * @initialVersion 5.0.0 + * @api enums + */ OBS_WEBSOCKET_OUTPUT_STOPPED, + /** + * The output has disconnected and is reconnecting. + * + * @enumIdentifier OBS_WEBSOCKET_OUTPUT_RECONNECTING + * @enumType ObsOutputState + * @rpcVersion 1 + * @initialVersion 5.0.0 + * @api enums + */ OBS_WEBSOCKET_OUTPUT_RECONNECTING, + /** + * The output has reconnected successfully. + * + * @enumIdentifier OBS_WEBSOCKET_OUTPUT_RECONNECTED + * @enumType ObsOutputState + * @rpcVersion 1 + * @initialVersion 5.1.0 + * @api enums + */ + OBS_WEBSOCKET_OUTPUT_RECONNECTED, + /** + * The output is now paused. + * + * @enumIdentifier OBS_WEBSOCKET_OUTPUT_PAUSED + * @enumType ObsOutputState + * @rpcVersion 1 + * @initialVersion 5.1.0 + * @api enums + */ OBS_WEBSOCKET_OUTPUT_PAUSED, + /** + * The output has been resumed (unpaused). + * + * @enumIdentifier OBS_WEBSOCKET_OUTPUT_RESUMED + * @enumType ObsOutputState + * @rpcVersion 1 + * @initialVersion 5.0.0 + * @api enums + */ OBS_WEBSOCKET_OUTPUT_RESUMED, }; - NLOHMANN_JSON_SERIALIZE_ENUM(ObsOutputState, { {OBS_WEBSOCKET_OUTPUT_UNKNOWN, "OBS_WEBSOCKET_OUTPUT_UNKNOWN"}, {OBS_WEBSOCKET_OUTPUT_STARTING, "OBS_WEBSOCKET_OUTPUT_STARTING"}, {OBS_WEBSOCKET_OUTPUT_STARTED, "OBS_WEBSOCKET_OUTPUT_STARTED"}, {OBS_WEBSOCKET_OUTPUT_STOPPING, "OBS_WEBSOCKET_OUTPUT_STOPPING"}, {OBS_WEBSOCKET_OUTPUT_STOPPED, "OBS_WEBSOCKET_OUTPUT_STOPPED"}, + {OBS_WEBSOCKET_OUTPUT_RECONNECTING, "OBS_WEBSOCKET_OUTPUT_RECONNECTING"}, + {OBS_WEBSOCKET_OUTPUT_RECONNECTED, "OBS_WEBSOCKET_OUTPUT_RECONNECTED"}, {OBS_WEBSOCKET_OUTPUT_PAUSED, "OBS_WEBSOCKET_OUTPUT_PAUSED"}, {OBS_WEBSOCKET_OUTPUT_RESUMED, "OBS_WEBSOCKET_OUTPUT_RESUMED"}, }) @@ -159,7 +242,6 @@ */ OBS_WEBSOCKET_MEDIA_INPUT_ACTION_PREVIOUS, }; - NLOHMANN_JSON_SERIALIZE_ENUM(ObsMediaInputAction, { {OBS_WEBSOCKET_MEDIA_INPUT_ACTION_NONE, "OBS_WEBSOCKET_MEDIA_INPUT_ACTION_NONE"}, @@ -181,6 +263,7 @@ std::string GetCurrentRecordOutputPath(); std::string GetLastRecordFileName(); std::string GetLastReplayBufferFileName(); + std::string GetLastScreenshotFileName(); std::string DurationToTimecode(uint64_t); }
View file
obs-studio-28.1.2.tar.xz/plugins/obs-websocket/src/utils/Obs_StringHelper.cpp -> obs-studio-29.0.0.tar.xz/plugins/obs-websocket/src/utils/Obs_StringHelper.cpp
Changed
@@ -94,20 +94,18 @@ std::string Utils::Obs::StringHelper::GetLastReplayBufferFileName() { - OBSOutputAutoRelease output = obs_frontend_get_replay_buffer_output(); - if (!output) - return ""; - - calldata_t cd = {0}; - proc_handler_t *ph = obs_output_get_proc_handler(output); - proc_handler_call(ph, "get_last_replay", &cd); - const char *savedReplayPath = calldata_string(&cd, "path"); - calldata_free(&cd); - - if (!savedReplayPath) - return ""; + char *replayBufferPath = obs_frontend_get_last_replay(); + std::string ret = replayBufferPath; + bfree(replayBufferPath); + return ret; +} - return savedReplayPath; +std::string Utils::Obs::StringHelper::GetLastScreenshotFileName() +{ + char *screenshotPath = obs_frontend_get_last_screenshot(); + std::string ret = screenshotPath; + bfree(screenshotPath); + return ret; } std::string Utils::Obs::StringHelper::DurationToTimecode(uint64_t ms)
View file
obs-studio-28.1.2.tar.xz/plugins/obs-x264/obs-x264.c -> obs-studio-29.0.0.tar.xz/plugins/obs-x264/obs-x264.c
Changed
@@ -361,7 +361,7 @@ struct obs_x264 *obsx264 = param; char str1024; - vsnprintf(str, 1024, format, args); + vsnprintf(str, sizeof(str), format, args); info("%s", str); UNUSED_PARAMETER(level);
View file
obs-studio-28.1.2.tar.xz/plugins/rtmp-services/CMakeLists.txt -> obs-studio-29.0.0.tar.xz/plugins/rtmp-services/CMakeLists.txt
Changed
@@ -43,6 +43,10 @@ rtmp-services.rc) target_sources(rtmp-services PRIVATE rtmp-services.rc) + + if(MSVC) + target_link_options(rtmp-services PRIVATE "LINKER:/IGNORE:4098") + endif() endif() set_target_properties(rtmp-services PROPERTIES FOLDER "plugins" PREFIX "")
View file
obs-studio-28.1.2.tar.xz/plugins/rtmp-services/data/package.json -> obs-studio-29.0.0.tar.xz/plugins/rtmp-services/data/package.json
Changed
@@ -1,11 +1,11 @@ { "$schema": "schema/package-schema.json", - "url": "https://obsproject.com/obs2_update/rtmp-services", - "version": 211, + "url": "https://obsproject.com/obs2_update/rtmp-services/v4", + "version": 216, "files": { "name": "services.json", - "version": 211 + "version": 216 } }
View file
obs-studio-29.0.0.tar.xz/plugins/rtmp-services/data/schema/service-schema-v4.json
Added
@@ -0,0 +1,239 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "properties": { + "format_version": { + "type": "integer", + "description": "Identifier for parsing this file.\n- v4 introduced 'ffmpeg_mpegts_muxer' to services/recommended/output\n - v3 introduced 'ffmpeg_hls_muxer' to services/recommended/output\n - v2 introduced 'alt_names' to services" + }, + "services": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Name of the streaming service. Will be displayed in the Service dropdown.", + "minLength": 1 + }, + "common": { + "type": "boolean", + "description": "Whether or not the service is shown in the list before it is expanded to all services by the user.", + "default": false + }, + "stream_key_link": { + "$ref": "#/definitions/saneUrl", + "description": "Link where a logged-in user can find the 'stream key', presented as a button alongside the stream key field." + }, + "supported video codecs": { + "type": "array", + "description": "Video codecs that are supported by the service.", + "items": { + "type": "string", + "description": "Short-form codec names.", + "minLength": 1, + "enum": + "h264", + "hevc" + + } + }, + "supported audio codecs": { + "type": "array", + "description": "Audio codecs that are supported by the service.", + "items": { + "type": "string", + "description": "Short-form codec names.", + "minLength": 1, + "enum": + "aac", + "opus" + + } + }, + "servers": { + "type": "array", + "description": "List of servers.", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Name of the server (e.g. location, primary/backup), displayed in the Server dropdown.", + "minLength": 1 + }, + "url": { + "$ref": "#/definitions/serviceUri", + "description": "RTMP(S) or HLS URL of the ingest server.", + "minLength": 1 + } + }, + "additionalProperties": false, + "required": + "name", + "url" + + }, + "default": + { + "name": "", + "url": "" + } + , + "minItems": 1, + "additionalItems": true + }, + "recommended": { + "type": "object", + "description": "Recommended service settings. Users will be unable to choose values outside of these by default, so choose recommended values carefully.", + "properties": { + "keyint": { + "type": "integer", + "description": "Keyframe interval (seconds)." + }, + "max video bitrate": { + "type": "integer", + "description": "Highest supported video bitrate (kbps)." + }, + "max audio bitrate": { + "type": "integer", + "description": "Highest supported audio bitrate (kbps)." + }, + "x264opts": { + "type": "string", + "description": "Additional x264 encoder options. Space-separated.", + "pattern": "^(\\S+=\\S+\\s*)+$" + }, + "output": { + "type": "string", + "description": "OBS output module used.", + "enum": + "rtmp_output", + "ffmpeg_hls_muxer", + "ftl_output", + "ffmpeg_mpegts_muxer" + + }, + "profile": { + "type": "string", + "description": "H.264 Profile.", + "minLength": 1, + "enum": + "high", + "main", + "baseline" + + }, + "bframes": { + "type": "integer", + "description": "Maximum allowed number of B-Frames." + }, + "supported resolutions": { + "type": "array", + "description": "List of supported resolutions in format {width}x{height}", + "items": { + "$ref": "#/definitions/resolution" + }, + "minItems": 1, + "additionalItems": true + }, + "max fps": { + "type": "integer", + "description": "Maximum supported framerate." + }, + "bitrate matrix": { + "type": "array", + "description": "List of resolutions and frame rate combinations with their recommended maximum bitrate.", + "items": { + "type": "object", + "properties": { + "res": { + "$ref": "#/definitions/resolution", + "description": "Resolution in format {width}x{height}" + }, + "fps": { + "type": "integer", + "description": "Frame rate" + }, + "max bitrate": { + "type": "integer", + "description": "Maximum bitrate in kbps." + } + }, + "minItems": 1, + "additionalProperties": false, + "required": + "res", + "fps", + "max bitrate" + + }, + "default": + { + "res": "", + "fps": "", + "max bitrate": "" + } + , + "additionalItems": true + } + }, + "additionalProperties": false + }, + "more_info_link": { + "$ref": "#/definitions/saneUrl", + "description": "Link that provides additional info about the service, presented in the UI as a button next to the services dropdown." + }, + "alt_names": { + "type": "array", + "description": "Previous names of the service used for migrating existing users to the updated entry.", + "items": { + "type": "string", + "minLength": 1 + }, + "default": + "" + + } + }, + "additionalProperties": false, + "required": + "name", + "servers" + + }, + "additionalItems": true + } + }, + "additionalProperties": true, + "required": + "format_version", + "services" + , + "definitions": { + "resolution": { + "type": "string", + "pattern": "^\\d+x\\d+$", + "default": "" + }, + "saneUrl": { + "type": "string", + "format": "uri", + "pattern": "^https?://.+", + "default": "https://" + }, + "serviceUri": { + "anyOf": + { + "type": "string", + "format": "uri", + "pattern": "^(https|http|rtmps|rtmp|srt|rist)?://" + }, + { + "type": "string", + "format": "hostname" + } + + } + } +}
View file
obs-studio-28.1.2.tar.xz/plugins/rtmp-services/data/services.json -> obs-studio-29.0.0.tar.xz/plugins/rtmp-services/data/services.json
Changed
@@ -1,6 +1,6 @@ { - "$schema": "schema/service-schema-v3.json", - "format_version": 3, + "$schema": "schema/service-schema-v4.json", + "format_version": 4, "services": { "name": "Twitch", @@ -2072,29 +2072,6 @@ } }, { - "name": "Brime Live", - "stream_key_link": "https://brime.tv/studio", - "servers": - { - "name": "North America - Ashburn, VA", - "url": "rtmp://ingest-us-ashburn.brime.tv/live" - }, - { - "name": "North America - San Jose, CA", - "url": "rtmp://ingest-us-sanjose.brime.tv/live" - }, - { - "name": "Europe / EMEA - Germany (Frankfurt)", - "url": "rtmp://ingest-eu-frankfurt.brime.tv/live" - } - , - "recommended": { - "max video bitrate": 30000, - "max audio bitrate": 320, - "x264opts": "scenecut=0" - } - }, - { "name": "Bilibili Live - RTMP | 哔哩哔哩直播 - RTMP", "more_info_link": "https://link.bilibili.com/p/help/index#/tools-tutorial?id=9", "stream_key_link": "https://link.bilibili.com/p/center/index#/my-room/start-live", @@ -2546,6 +2523,71 @@ "max video bitrate": 20000, "max audio bitrate": 192 } + }, + { + "name": "Whowatch (ふわっち)", + "more_info_link": "https://whowatch.tv/help/encoder", + "stream_key_link": "https://whowatch.tv/publish", + "servers": + { + "name": "default", + "url": "rtmp://live.whowatch.tv/live/" + } + , + "recommended": { + "keyint": 2, + "max video bitrate": 1800, + "max audio bitrate": 192 + } + }, + { + "name": "IRLToolkit", + "stream_key_link": "https://irl.run/settings/ingest/", + "servers": + { + "name": "Global (Recommended)", + "url": "rtmp://stream.global.irl.run/ingest" + }, + { + "name": "Los Angeles, US", + "url": "rtmp://stream.lax.irl.run/ingest" + }, + { + "name": "New York, US", + "url": "rtmp://stream.ewr.irl.run/ingest" + }, + { + "name": "Rotterdam, NL", + "url": "rtmp://stream.rtm.irl.run/ingest" + }, + { + "name": "Singapore", + "url": "rtmp://stream.sin.irl.run/ingest" + }, + { + "name": "Tokyo, JP", + "url": "rtmp://stream.tyo.irl.run/ingest" + } + , + "recommended": { + "keyint": 2, + "bframes": 2, + "max video bitrate": 20000 + } + }, + { + "name": "Bitmovin", + "more_info_link": "https://developer.bitmovin.com/docs/overview", + "stream_key_link": "https://bitmovin.com/dashboard/streams?streamsTab=LIVE", + "servers": + { + "name": "Streams Live", + "url": "rtmp://live-input.bitmovin.com/streams" + } + , + "recommended": { + "keyint": 2 + } } }
View file
obs-studio-28.1.2.tar.xz/plugins/rtmp-services/rtmp-format-ver.h -> obs-studio-29.0.0.tar.xz/plugins/rtmp-services/rtmp-format-ver.h
Changed
@@ -1,3 +1,3 @@ #pragma once -#define RTMP_SERVICES_FORMAT_VERSION 3 +#define RTMP_SERVICES_FORMAT_VERSION 4
View file
obs-studio-28.1.2.tar.xz/plugins/win-capture/cursor-capture.c -> obs-studio-29.0.0.tar.xz/plugins/win-capture/cursor-capture.c
Changed
@@ -107,14 +107,19 @@ bottom = bmp.bmWidthBytes * bmp.bmHeight; for (long i = 0; i < pixels; i++) { - uint8_t alpha = bit_to_alpha(mask, i, false); - uint8_t color = bit_to_alpha(mask + bottom, i, true); - - if (!alpha) { - outputi * 4 + 3 = color; + uint8_t andMask = bit_to_alpha(mask, i, true); + uint8_t xorMask = bit_to_alpha(mask + bottom, i, true); + + if (!andMask) { + // black in the AND mask + *(uint32_t *)&outputi * 4 = + !!xorMask ? 0x00FFFFFF /*always white*/ + : 0xFF000000 /*always black*/; } else { - *(uint32_t *)&outputi * 4 = !!color ? 0xFFFFFFFF - : 0xFF000000; + // white in the AND mask + *(uint32_t *)&outputi * 4 = + !!xorMask ? 0xFFFFFFFF /*source inverted*/ + : 0 /*transparent*/; } } @@ -126,13 +131,16 @@ } static inline uint8_t *cursor_capture_icon_bitmap(ICONINFO *ii, uint32_t *width, - uint32_t *height) + uint32_t *height, + bool *monochrome) { uint8_t *output; - + *monochrome = false; output = copy_from_color(ii, width, height); - if (!output) + if (!output) { + *monochrome = true; output = copy_from_mask(ii, width, height); + } return output; } @@ -170,7 +178,8 @@ return false; } - bitmap = cursor_capture_icon_bitmap(&ii, &width, &height); + bitmap = cursor_capture_icon_bitmap(&ii, &width, &height, + &data->monochrome); if (bitmap) { if (data->last_cx != width || data->last_cy != height) { data->texture = get_cached_texture(data, width, height); @@ -228,9 +237,13 @@ if (data->visible && !!data->texture) { gs_blend_state_push(); - gs_blend_function_separate(GS_BLEND_SRCALPHA, - GS_BLEND_INVSRCALPHA, GS_BLEND_ONE, - GS_BLEND_INVSRCALPHA); + enum gs_blend_type blendMode = data->monochrome + ? GS_BLEND_INVDSTCOLOR + : GS_BLEND_SRCALPHA; + gs_blend_function_separate(blendMode, /*src_color*/ + GS_BLEND_INVSRCALPHA /*dest_color*/, + GS_BLEND_ONE /*src_alpha*/, + GS_BLEND_INVSRCALPHA /*dest_alpha*/); gs_matrix_push(); obs_source_draw(data->texture, x_draw, y_draw, 0, 0, false);
View file
obs-studio-28.1.2.tar.xz/plugins/win-capture/cursor-capture.h -> obs-studio-29.0.0.tar.xz/plugins/win-capture/cursor-capture.h
Changed
@@ -15,6 +15,7 @@ long x_hotspot; long y_hotspot; bool visible; + bool monochrome; uint32_t last_cx; uint32_t last_cy;
View file
obs-studio-28.1.2.tar.xz/plugins/win-capture/duplicator-monitor-capture.c -> obs-studio-29.0.0.tar.xz/plugins/win-capture/duplicator-monitor-capture.c
Changed
@@ -68,8 +68,8 @@ struct duplicator_capture { obs_source_t *source; pthread_mutex_t update_mutex; - int monitor; - int dxgi_index; + char monitor_id128; + char monitor_name64; enum display_capture_method method; bool reset_wgc; HMONITOR handle; @@ -93,9 +93,8 @@ }; struct wgc_monitor_info { - int cur_id; - int desired_id; - int id; + char device_id128; + char name64; RECT rect; HMONITOR handle; }; @@ -117,49 +116,128 @@ return method_name; } +static bool GetMonitorTarget(LPCWSTR device, + DISPLAYCONFIG_TARGET_DEVICE_NAME *target) +{ + bool found = false; + + UINT32 numPath, numMode; + if (GetDisplayConfigBufferSizes(QDC_ONLY_ACTIVE_PATHS, &numPath, + &numMode) == ERROR_SUCCESS) { + DISPLAYCONFIG_PATH_INFO *paths = + bmalloc(numPath * sizeof(DISPLAYCONFIG_PATH_INFO)); + DISPLAYCONFIG_MODE_INFO *modes = + bmalloc(numMode * sizeof(DISPLAYCONFIG_MODE_INFO)); + if (QueryDisplayConfig(QDC_ONLY_ACTIVE_PATHS, &numPath, paths, + &numMode, modes, + NULL) == ERROR_SUCCESS) { + for (size_t i = 0; i < numPath; ++i) { + const DISPLAYCONFIG_PATH_INFO *const path = + &pathsi; + + DISPLAYCONFIG_SOURCE_DEVICE_NAME + source; + source.header.type = + DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME; + source.header.size = sizeof(source); + source.header.adapterId = + path->sourceInfo.adapterId; + source.header.id = path->sourceInfo.id; + if (DisplayConfigGetDeviceInfo( + &source.header) == ERROR_SUCCESS && + wcscmp(device, source.viewGdiDeviceName) == + 0) { + target->header.type = + DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME; + target->header.size = sizeof(*target); + target->header.adapterId = + path->sourceInfo.adapterId; + target->header.id = path->targetInfo.id; + found = DisplayConfigGetDeviceInfo( + &target->header) == + ERROR_SUCCESS; + break; + } + } + } + + bfree(modes); + bfree(paths); + } + + return found; +} + +static void GetMonitorName(HMONITOR handle, char *name, size_t count) +{ + MONITORINFOEXW mi; + DISPLAYCONFIG_TARGET_DEVICE_NAME target; + + mi.cbSize = sizeof(mi); + if (GetMonitorInfoW(handle, (LPMONITORINFO)&mi) && + GetMonitorTarget(mi.szDevice, &target)) { + snprintf(name, count, "%ls", target.monitorFriendlyDeviceName); + } else { + strcpy_s(name, count, "OBS: Unknown"); + } +} + static BOOL CALLBACK enum_monitor(HMONITOR handle, HDC hdc, LPRECT rect, LPARAM param) { + UNUSED_PARAMETER(hdc); + struct wgc_monitor_info *monitor = (struct wgc_monitor_info *)param; - if (monitor->cur_id == 0 || monitor->desired_id == monitor->cur_id) { - monitor->id = monitor->cur_id; - monitor->rect = *rect; - monitor->handle = handle; + bool match = false; + + MONITORINFOEXA mi; + mi.cbSize = sizeof(mi); + if (GetMonitorInfoA(handle, (LPMONITORINFO)&mi)) { + DISPLAY_DEVICEA device; + device.cb = sizeof(device); + if (EnumDisplayDevicesA(mi.szDevice, 0, &device, + EDD_GET_DEVICE_INTERFACE_NAME)) { + const bool match = strcmp(monitor->device_id, + device.DeviceID) == 0; + if (match) { + monitor->rect = *rect; + monitor->handle = handle; + GetMonitorName(handle, monitor->name, + _countof(monitor->name)); + } + } } - UNUSED_PARAMETER(hdc); - return (monitor->desired_id > monitor->cur_id++); + return !match; } -static void log_settings(struct duplicator_capture *capture, int monitor, - LONG width, LONG height) +static void log_settings(struct duplicator_capture *capture, + const char *monitor, LONG width, LONG height) { info("update settings:\n" - "\tdisplay: %d (%ldx%ld)\n" + "\tdisplay: %s (%ldx%ld)\n" "\tcursor: %s\n" "\tmethod: %s", - monitor + 1, width, height, - capture->capture_cursor ? "true" : "false", + monitor, width, height, capture->capture_cursor ? "true" : "false", get_method_name(capture->method)); } static enum display_capture_method choose_method(enum display_capture_method method, bool wgc_supported, - HMONITOR monitor, int *dxgi_index) + HMONITOR monitor) { if (!wgc_supported) method = METHOD_DXGI; - if (method != METHOD_WGC) { + if (method == METHOD_AUTO) { + method = METHOD_DXGI; + obs_enter_graphics(); - *dxgi_index = gs_duplicator_get_monitor_index(monitor); + const int dxgi_index = gs_duplicator_get_monitor_index(monitor); obs_leave_graphics(); - } - if (method == METHOD_AUTO) { - method = METHOD_DXGI; - if (*dxgi_index == -1) { + if (dxgi_index == -1) { method = METHOD_WGC; } else { SYSTEM_POWER_STATUS status; @@ -185,14 +263,18 @@ pthread_mutex_lock(&capture->update_mutex); struct wgc_monitor_info monitor = {0}; - monitor.desired_id = (int)obs_data_get_int(settings, "monitor"); + strcpy_s(monitor.device_id, _countof(monitor.device_id), + obs_data_get_string(settings, "monitor_id")); EnumDisplayMonitors(NULL, NULL, enum_monitor, (LPARAM)&monitor); - capture->method = choose_method( - (int)obs_data_get_int(settings, "method"), wgc_supported, - monitor.handle, &capture->dxgi_index); + capture->method = + choose_method((int)obs_data_get_int(settings, "method"), + wgc_supported, monitor.handle); - capture->monitor = monitor.id; + strcpy_s(capture->monitor_id, _countof(capture->monitor_id), + monitor.device_id); + strcpy_s(capture->monitor_name, _countof(capture->monitor_name), + monitor.name); capture->handle = monitor.handle; capture->capture_cursor = obs_data_get_bool(settings, "capture_cursor"); @@ -266,7 +348,7 @@ static void duplicator_capture_defaults(obs_data_t *settings) { obs_data_set_default_int(settings, "method", METHOD_AUTO); - obs_data_set_default_int(settings, "monitor", 0); + obs_data_set_default_string(settings, "monitor_id", "DUMMY"); obs_data_set_default_int(settings, "monitor_wgc", 0); obs_data_set_default_bool(settings, "capture_cursor", true); } @@ -275,7 +357,7 @@ { struct duplicator_capture *mc = data; update_settings(mc, settings); - log_settings(mc, mc->monitor, mc->logged_width, mc->logged_height); + log_settings(mc, mc->monitor_name, mc->logged_width, mc->logged_height); mc->reset_wgc = true; } @@ -332,7 +414,7 @@ } update_settings(capture, settings); - log_settings(capture, capture->monitor, capture->logged_width, + log_settings(capture, capture->monitor_name, capture->logged_width, capture->logged_height); return capture; @@ -343,7 +425,8 @@ struct gs_monitor_info monitor_info = {0}; gs_texture_t *texture = gs_duplicator_get_texture(capture->duplicator); - gs_get_duplicator_monitor_info(capture->dxgi_index, &monitor_info); + const int dxgi_index = gs_duplicator_get_monitor_index(capture->handle); + gs_get_duplicator_monitor_info(dxgi_index, &monitor_info); if (texture) { capture->width = gs_texture_get_width(texture); capture->height = gs_texture_get_height(texture); @@ -378,6 +461,15 @@ capture->reset_timeout = 0.0f; } +static void update_monitor_handle(struct duplicator_capture *capture) +{ + struct wgc_monitor_info monitor = {0}; + strcpy_s(monitor.device_id, _countof(monitor.device_id), + capture->monitor_id); + EnumDisplayMonitors(NULL, NULL, enum_monitor, (LPARAM)&monitor); + capture->handle = monitor.handle; +} + static void duplicator_capture_tick(void *data, float seconds) { struct duplicator_capture *capture = data; @@ -416,11 +508,25 @@ capture->reset_timeout += seconds; if (capture->reset_timeout >= RESET_INTERVAL_SEC) { - capture->capture_winrt = - capture->exports - .winrt_capture_init_monitor( + if (!capture->handle) + update_monitor_handle(capture); + + if (capture->handle) { + capture->capture_winrt = + capture->exports.winrt_capture_init_monitor( capture->capture_cursor, capture->handle); + if (!capture->capture_winrt) { + update_monitor_handle(capture); + + if (capture->handle) { + capture->capture_winrt = + capture->exports.winrt_capture_init_monitor( + capture->capture_cursor, + capture->handle); + } + } + } capture->reset_timeout = 0.0f; } @@ -436,8 +542,29 @@ capture->reset_timeout += seconds; if (capture->reset_timeout >= RESET_INTERVAL_SEC) { - capture->duplicator = gs_duplicator_create( - capture->dxgi_index); + if (!capture->handle) + update_monitor_handle(capture); + + if (capture->handle) { + int dxgi_index = + gs_duplicator_get_monitor_index( + capture->handle); + + if (dxgi_index == -1) { + update_monitor_handle(capture); + + if (capture->handle) { + dxgi_index = gs_duplicator_get_monitor_index( + capture->handle); + } + } + + if (dxgi_index != -1) { + capture->duplicator = + gs_duplicator_create( + dxgi_index); + } + } capture->reset_timeout = 0.0f; } @@ -600,38 +727,42 @@ UNUSED_PARAMETER(hdc); UNUSED_PARAMETER(rect); - obs_property_t *monitor_list = (obs_property_t *)param; - MONITORINFO mi; - size_t monitor_id = 0; - struct dstr monitor_desc = {0}; - struct dstr resolution = {0}; - struct dstr format_string = {0}; - - monitor_id = obs_property_list_item_count(monitor_list); - + MONITORINFOEXA mi; mi.cbSize = sizeof(mi); - GetMonitorInfo(handle, &mi); + if (GetMonitorInfoA(handle, (LPMONITORINFO)&mi)) { + DISPLAY_DEVICEA device; + device.cb = sizeof(device); + if (EnumDisplayDevicesA(mi.szDevice, 0, &device, + EDD_GET_DEVICE_INTERFACE_NAME)) { + obs_property_t *monitor_list = (obs_property_t *)param; + struct dstr monitor_desc = {0}; + struct dstr resolution = {0}; + + dstr_catf(&resolution, "%dx%d @ %d,%d", + mi.rcMonitor.right - mi.rcMonitor.left, + mi.rcMonitor.bottom - mi.rcMonitor.top, + mi.rcMonitor.left, mi.rcMonitor.top); + + char monitor_name64; + GetMonitorName(handle, monitor_name, + sizeof(monitor_name)); + dstr_catf(&monitor_desc, "%s: %s", monitor_name, + resolution.array); + + if (mi.dwFlags == MONITORINFOF_PRIMARY) { + dstr_catf(&monitor_desc, " (%s)", + TEXT_PRIMARY_MONITOR); + } - dstr_catf(&resolution, "%dx%d @ %d,%d", - mi.rcMonitor.right - mi.rcMonitor.left, - mi.rcMonitor.bottom - mi.rcMonitor.top, mi.rcMonitor.left, - mi.rcMonitor.top); + obs_property_list_add_string(monitor_list, + monitor_desc.array, + device.DeviceID); - dstr_copy(&format_string, "%s %d: %s"); - if (mi.dwFlags == MONITORINFOF_PRIMARY) { - dstr_catf(&format_string, " (%s)", TEXT_PRIMARY_MONITOR); + dstr_free(&monitor_desc); + dstr_free(&resolution); + } } - dstr_catf(&monitor_desc, format_string.array, TEXT_MONITOR, - monitor_id + 1, resolution.array); - - obs_property_list_add_int(monitor_list, monitor_desc.array, - (int)monitor_id); - - dstr_free(&monitor_desc); - dstr_free(&resolution); - dstr_free(&format_string); - return TRUE; } @@ -689,8 +820,8 @@ obs_property_set_modified_callback(p, display_capture_method_changed); obs_property_t *monitors = obs_properties_add_list( - props, "monitor", TEXT_MONITOR, OBS_COMBO_TYPE_LIST, - OBS_COMBO_FORMAT_INT); + props, "monitor_id", TEXT_MONITOR, OBS_COMBO_TYPE_LIST, + OBS_COMBO_FORMAT_STRING); obs_properties_add_bool(props, "capture_cursor", TEXT_CAPTURE_CURSOR);
View file
obs-studio-28.1.2.tar.xz/plugins/win-capture/game-capture.c -> obs-studio-29.0.0.tar.xz/plugins/win-capture/game-capture.c
Changed
@@ -823,7 +823,7 @@ static inline bool init_pipe(struct game_capture *gc) { char name64; - sprintf(name, "%s%lu", PIPE_NAME, gc->process_id); + snprintf(name, sizeof(name), "%s%lu", PIPE_NAME, gc->process_id); if (!ipc_pipe_server_start(&gc->pipe, name, pipe_log, gc)) { warn("init_pipe: failed to start pipe");
View file
obs-studio-28.1.2.tar.xz/plugins/win-capture/get-graphics-offsets/d3d9-offsets.cpp -> obs-studio-29.0.0.tar.xz/plugins/win-capture/get-graphics-offsets/d3d9-offsets.cpp
Changed
@@ -83,15 +83,32 @@ #define MAX_CMP_SIZE 22 +// clang-format off static const uint8_t maskMAX_CMP_SIZE = { - {0xF8, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xFF, 0x00, 0xF8, 0xF8, 0x00, 0x00, 0x00, 0x00}, - {0xF8, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xC0, 0x00, 0x00, - 0x00, 0x00, 0xFF, 0x00, 0xF8, 0xF8, 0x00, 0x00, 0x00, 0x00}, - {0xF8, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xC0, 0x00, 0x00, - 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00}, - {0xF8, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xC0, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00}, + { + 0xF8, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0x00, + 0xF8, 0xF8, 0x00, 0x00, 0x00, 0x00 + }, + { + 0xF8, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0x00, + 0xF8, 0xF8, 0x00, 0x00, 0x00, 0x00 + }, + { + 0xF8, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0x00, + 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00 + }, + { + 0xF8, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0x00, + 0xFF, 0xFF, 0x00, 0x00, 0x00 + }, }; static const uint8_t mask_cmpMAX_CMP_SIZE = { @@ -102,8 +119,12 @@ * 75 12 jnz short loc_7FF7AA90530 * 41 B8 F9 19 00 00 mov r8d, 19F9h */ - {0x48, 0x8B, 0x80, 0x00, 0x00, 0x00, 0x00, 0x44, 0x39, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x75, 0x00, 0x40, 0xB8, 0x00, 0x00, 0x00, 0x00}, + { + 0x48, 0x8B, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x44, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x75, 0x00, + 0x40, 0xB8, 0x00, 0x00, 0x00, 0x00 + }, /* * Windows ???+ * 49 8B 87 78 41 00 00 mov rax, r15+4178h @@ -111,8 +132,12 @@ * 75 12 jnz short loc_1800AEC9C * 41 B9 C3 1A 00 00 mov r9d, 1AC3h */ - {0x48, 0x8B, 0x80, 0x00, 0x00, 0x00, 0x00, 0x39, 0x80, 0x00, 0x00, - 0x00, 0x00, 0x75, 0x00, 0x40, 0xB8, 0x00, 0x00, 0x00, 0x00}, + { + 0x48, 0x8B, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x39, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x75, 0x00, + 0x40, 0xB8, 0x00, 0x00, 0x00, 0x00 + }, /* * Windows 10 April 2018 * 49 8B 87 58 40 00 00 mov rax, r15+4058h @@ -122,8 +147,12 @@ * * Note: different instructions, last byte skipped due to MAX_CMP_SIZE */ - {0x48, 0x8B, 0x80, 0x00, 0x00, 0x00, 0x00, 0x39, 0x80, 0x00, 0x00, - 0x00, 0x00, 0x75, 0x00, 0x48, 0x8D, 0x00, 0x00, 0x00, 0x00}, + { + 0x48, 0x8B, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x39, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x75, 0x00, + 0x48, 0x8D, 0x00, 0x00, 0x00, 0x00 + }, /* * Windows 11 22H2 * 49 8b 86 30 40 00 00 MOV RAX,qword ptr R14 + 0x4030 @@ -133,9 +162,14 @@ * * Note: different instructions, last byte skipped due to MAX_CMP_SIZE */ - {0x48, 0x8B, 0x80, 0x00, 0x00, 0x00, 0x00, 0x83, 0x80, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x75, 0x00, 0x48, 0x8D, 0x00, 0x00, 0x00}, + { + 0x48, 0x8B, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x83, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x75, 0x00, + 0x48, 0x8D, 0x00, 0x00, 0x00 + }, }; +// clang-format on // Offset into the code for the numbers we're interested in static const uint32_t code_offsets2 = { @@ -148,15 +182,32 @@ #define MAX_CMP_SIZE 20 +// clang-format off static const uint8_t maskMAX_CMP_SIZE = { - {0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, - 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00}, - {0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xC0, 0x00, 0x00, - 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00}, - {0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xC0, 0x00, 0x00, - 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00}, - {0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xC0, 0x00, 0x00, - 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00}, + { + 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0x00, + 0xFF, 0x00, 0x00, 0x00, 0x00 + }, + { + 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0xFF, + 0xFF, 0x00, + 0xFF, 0x00, 0x00, 0x00, 0x00 + }, + { + 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0xFF, + 0xFF, 0x00, + 0xFF, 0x00, 0x00, 0x00, 0x00 + }, + { + 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0x00, + 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00 + }, }; static const uint8_t mask_cmpMAX_CMP_SIZE = { @@ -167,18 +218,24 @@ * 75 14 jnz short loc_754CD9E1 * 68 F9 19 00 00 push 19F9h */ - {0x8B, 0x80, 0x00, 0x00, 0x00, 0x00, 0x39, 0x80, 0x00, 0x00, 0x00, 0x00, - 0x75, 0x00, 0x68, 0x00, 0x00, 0x00, 0x00}, - + { + 0x8B, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x39, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x75, 0x00, + 0x68, 0x00, 0x00, 0x00, 0x00 + }, /* Windows 10 Creator's Update+ * 8B 86 F8 2B 00 00 mov eax, esi+2BF8h * 83 B8 00 4D 00 00 00 cmp dword ptr eax+4D00h, 0 * 75 0F jnz short loc_100D793C * 68 C3 1A 00 00 push 1AC3h */ - {0x8B, 0x80, 0x00, 0x00, 0x00, 0x00, 0x83, 0x80, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x75, 0x00, 0x68, 0x00, 0x00, 0x00, 0x00}, - + { + 0x8B, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x83, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x75, 0x00, + 0x68, 0x00, 0x00, 0x00, 0x00 + }, /* * Windows 10 April 2018 Update * 8B 86 68 2B 00 00 mov eax, esi+2B68h @@ -186,9 +243,12 @@ * 75 0F jnz short loc_100D9A9C * BA 08 71 01 10 mov edx, offset errMsg */ - {0x8B, 0x80, 0x00, 0x00, 0x00, 0x00, 0x83, 0x80, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x75, 0x00, 0xBA, 0x00, 0x00, 0x00, 0x00}, - + { + 0x8B, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x83, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x75, 0x00, + 0xBA, 0x00, 0x00, 0x00, 0x00 + }, /* * Windows 11 22H2 * 8b 83 3c 2b 00 00 MOV EAX,dword ptr EBX + 0x2b3c @@ -196,9 +256,14 @@ * 75 0f JNZ LAB_100d79a0 * ba d0 c6 00 10 MOV EDX,s_To_use_... */ - {0x8B, 0x80, 0x00, 0x00, 0x00, 0x00, 0x39, 0x80, 0x00, 0x00, - 0x00, 0x00, 0x75, 0x00, 0xBA, 0x00, 0x00, 0x00, 0x00, 0x00}, + { + 0x8B, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x39, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x75, 0x00, + 0xBA, 0x00, 0x00, 0x00, 0x00, 0x00 + }, }; +// clang-format on // Offset into the code for the numbers we're interested in static const uint32_t code_offsets2 = {
View file
obs-studio-28.1.2.tar.xz/plugins/win-capture/graphics-hook/graphics-hook.c -> obs-studio-29.0.0.tar.xz/plugins/win-capture/graphics-hook/graphics-hook.c
Changed
@@ -65,7 +65,8 @@ bool init_pipe(void) { char new_name64; - sprintf(new_name, "%s%lu", PIPE_NAME, GetCurrentProcessId()); + snprintf(new_name, sizeof(new_name), "%s%lu", PIPE_NAME, + GetCurrentProcessId()); const bool success = ipc_pipe_client_open(&pipe, new_name); if (!success) {
View file
obs-studio-28.1.2.tar.xz/plugins/win-dshow/ffmpeg-decode.c -> obs-studio-29.0.0.tar.xz/plugins/win-dshow/ffmpeg-decode.c
Changed
@@ -312,7 +312,7 @@ } bool ffmpeg_decode_video(struct ffmpeg_decode *decode, uint8_t *data, - size_t size, long long *ts, + size_t size, long long *ts, enum video_colorspace cs, enum video_range_type range, struct obs_source_frame2 *frame, bool *got_output) { @@ -396,9 +396,11 @@ : VIDEO_RANGE_PARTIAL; } - const enum video_colorspace cs = convert_color_space( - decode->frame->colorspace, decode->frame->color_trc, - decode->frame->color_primaries); + if (cs == VIDEO_CS_DEFAULT) { + cs = convert_color_space(decode->frame->colorspace, + decode->frame->color_trc, + decode->frame->color_primaries); + } const bool success = video_format_get_parameters_for_format( cs, range, format, frame->color_matrix, frame->color_range_min,
View file
obs-studio-28.1.2.tar.xz/plugins/win-dshow/ffmpeg-decode.h -> obs-studio-29.0.0.tar.xz/plugins/win-dshow/ffmpeg-decode.h
Changed
@@ -59,6 +59,7 @@ extern bool ffmpeg_decode_video(struct ffmpeg_decode *decode, uint8_t *data, size_t size, long long *ts, + enum video_colorspace cs, enum video_range_type range, struct obs_source_frame2 *frame, bool *got_output);
View file
obs-studio-29.0.0.tar.xz/plugins/win-dshow/libdshowcapture/external/.clang-format
Added
@@ -0,0 +1,3 @@ +Language: Cpp +SortIncludes: false +DisableFormat: true
View file
obs-studio-28.1.2.tar.xz/plugins/win-dshow/libdshowcapture/source/dshow-base.cpp -> obs-studio-29.0.0.tar.xz/plugins/win-dshow/libdshowcapture/source/dshow-base.cpp
Changed
@@ -694,6 +694,21 @@ L"3842", /* evga */ L"0B05", /* asus */ L"07CA", /* avermedia */ + L"048D", /* digitnow/pengo */ + L"04B4", /* mokose */ + L"0557", /* aten */ + L"1164", /* startek/kapchr */ + L"1532", /* razer */ + L"1BCF", /* mypin/treaslin/mirabox */ + L"1E4E", /* pengo/cloneralliance */ + L"1E71", /* nzxt */ + L"2040", /* hauppauge */ + L"2935", /* magewell */ + L"298F", /* genki */ + L"2B77", /* epiphan */ + L"32ED", /* ezcap */ + L"534D", /* brand-less/pacoxi/ucec */ + L"EBA4", /* zasluke */ }; if (MatchingStartToken(path, usbToken)) { @@ -711,6 +726,8 @@ const wstring pciSubsysToken = L"SUBSYS_"; const wstring pciVenIdWhitelist = { L"1CD7", /* magewell */ + L"8888", /* acasis */ + L"1461", /* avermedia */ }; const wstring pciSubsysIdWhitelist = { L"1CFA", /* elgato */
View file
obs-studio-28.1.2.tar.xz/plugins/win-dshow/virtualcam-module/virtualcam-filter.cpp -> obs-studio-29.0.0.tar.xz/plugins/win-dshow/virtualcam-module/virtualcam-filter.cpp
Changed
@@ -146,7 +146,7 @@ return hr; } - os_atomic_set_bool(&active, false); + os_atomic_set_bool(&active, true); SetEvent(thread_start); return S_OK; }
View file
obs-studio-28.1.2.tar.xz/plugins/win-dshow/win-dshow.cpp -> obs-studio-29.0.0.tar.xz/plugins/win-dshow/win-dshow.cpp
Changed
@@ -198,6 +198,7 @@ VideoConfig videoConfig; AudioConfig audioConfig; + enum video_colorspace cs; obs_source_frame2 frame; obs_source_audio audio; long lastRotation = 0; @@ -505,7 +506,7 @@ } bool got_output; - bool success = ffmpeg_decode_video(video_decoder, data, size, &ts, + bool success = ffmpeg_decode_video(video_decoder, data, size, &ts, cs, frame.range, &frame, &got_output); if (!success) { blog(LOG_WARNING, "Error decoding video"); @@ -1155,7 +1156,7 @@ if (device.Start() != Result::Success) return false; - const enum video_colorspace cs = GetColorSpace(settings); + cs = GetColorSpace(settings); const enum video_range_type range = GetColorRange(settings); enum video_trc trc = VIDEO_TRC_DEFAULT; @@ -1307,6 +1308,12 @@ }; static const FPSFormat validFPSFormats = { + {"360", MAKE_DSHOW_FPS(360)}, + {"240", MAKE_DSHOW_FPS(240)}, + {"144", MAKE_DSHOW_FPS(144)}, + {"120", MAKE_DSHOW_FPS(120)}, + {"119.88 NTSC", MAKE_DSHOW_FRACTIONAL_FPS(120000, 1001)}, + {"100", MAKE_DSHOW_FPS(100)}, {"60", MAKE_DSHOW_FPS(60)}, {"59.94 NTSC", MAKE_DSHOW_FRACTIONAL_FPS(60000, 1001)}, {"50", MAKE_DSHOW_FPS(50)},
Locations
Projects
Search
Status Monitor
Help
Open Build Service
OBS Manuals
API Documentation
OBS Portal
Reporting a Bug
Contact
Mailing List
Forums
Chat (IRC)
Twitter
Open Build Service (OBS)
is an
openSUSE project
.