New upstream version 24.0.5+dfsg1
This commit is contained in:
parent
52fa83f147
commit
4c2ea24267
61 changed files with 710 additions and 130 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -37,6 +37,7 @@ ipch/
|
||||||
GeneratedFiles/
|
GeneratedFiles/
|
||||||
.moc/
|
.moc/
|
||||||
/UI/obs.rc
|
/UI/obs.rc
|
||||||
|
.vscode/
|
||||||
|
|
||||||
/other/
|
/other/
|
||||||
|
|
||||||
|
|
|
@ -8,9 +8,12 @@ hr() {
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
# Generate file name variables
|
# Generate file name variables
|
||||||
|
export GIT_TAG=$(git describe --abbrev=0)
|
||||||
export GIT_HASH=$(git rev-parse --short HEAD)
|
export GIT_HASH=$(git rev-parse --short HEAD)
|
||||||
export FILE_DATE=$(date +%Y-%m-%d.%H-%M-%S)
|
export FILE_DATE=$(date +%Y-%m-%d.%H-%M-%S)
|
||||||
export FILENAME=$FILE_DATE-$GIT_HASH-$TRAVIS_BRANCH-osx.pkg
|
export FILENAME=$FILE_DATE-$GIT_HASH-$TRAVIS_BRANCH-osx.dmg
|
||||||
|
|
||||||
|
echo "git tag: $GIT_TAG"
|
||||||
|
|
||||||
cd ./build
|
cd ./build
|
||||||
|
|
||||||
|
@ -19,9 +22,9 @@ hr "Moving OBS LUA"
|
||||||
mv ./rundir/RelWithDebInfo/data/obs-scripting/obslua.so ./rundir/RelWithDebInfo/bin/
|
mv ./rundir/RelWithDebInfo/data/obs-scripting/obslua.so ./rundir/RelWithDebInfo/bin/
|
||||||
|
|
||||||
# Move obspython
|
# Move obspython
|
||||||
# hr "Moving OBS Python"
|
hr "Moving OBS Python"
|
||||||
# mv ./rundir/RelWithDebInfo/data/obs-scripting/_obspython.so ./rundir/RelWithDebInfo/bin/
|
mv ./rundir/RelWithDebInfo/data/obs-scripting/_obspython.so ./rundir/RelWithDebInfo/bin/
|
||||||
# mv ./rundir/RelWithDebInfo/data/obs-scripting/obspython.py ./rundir/RelWithDebInfo/bin/
|
mv ./rundir/RelWithDebInfo/data/obs-scripting/obspython.py ./rundir/RelWithDebInfo/bin/
|
||||||
|
|
||||||
# Package everything into a nice .app
|
# Package everything into a nice .app
|
||||||
hr "Packaging .app"
|
hr "Packaging .app"
|
||||||
|
@ -30,32 +33,44 @@ if [ -n "${TRAVIS_TAG}" ]; then
|
||||||
STABLE=true
|
STABLE=true
|
||||||
fi
|
fi
|
||||||
|
|
||||||
sudo python ../CI/install/osx/build_app.py --public-key ../CI/install/osx/OBSPublicDSAKey.pem --sparkle-framework ../../sparkle/Sparkle.framework --stable=$STABLE
|
#sudo python ../CI/install/osx/build_app.py --public-key ../CI/install/osx/OBSPublicDSAKey.pem --sparkle-framework ../../sparkle/Sparkle.framework --stable=$STABLE
|
||||||
|
|
||||||
|
../CI/install/osx/packageApp.sh
|
||||||
|
|
||||||
|
# fix obs outputs
|
||||||
|
cp /usr/local/opt/mbedtls/lib/libmbedtls.12.dylib ./OBS.app/Contents/Frameworks/
|
||||||
|
cp /usr/local/opt/mbedtls/lib/libmbedcrypto.3.dylib ./OBS.app/Contents/Frameworks/
|
||||||
|
cp /usr/local/opt/mbedtls/lib/libmbedx509.0.dylib ./OBS.app/Contents/Frameworks/
|
||||||
|
install_name_tool -change /usr/local/opt/mbedtls/lib/libmbedtls.12.dylib @executable_path/../Frameworks/libmbedtls.12.dylib ./OBS.app/Contents/Plugins/obs-outputs.so
|
||||||
|
install_name_tool -change /usr/local/opt/mbedtls/lib/libmbedcrypto.3.dylib @executable_path/../Frameworks/libmbedcrypto.3.dylib ./OBS.app/Contents/Plugins/obs-outputs.so
|
||||||
|
install_name_tool -change /usr/local/opt/mbedtls/lib/libmbedx509.0.dylib @executable_path/../Frameworks/libmbedx509.0.dylib ./OBS.app/Contents/Plugins/obs-outputs.so
|
||||||
|
install_name_tool -change /usr/local/opt/curl/lib/libcurl.4.dylib @executable_path/../Frameworks/libcurl.4.dylib ./OBS.app/Contents/Plugins/obs-outputs.so
|
||||||
|
install_name_tool -change @rpath/libobs.0.dylib @executable_path/../Frameworks/libobs.0.dylib ./OBS.app/Contents/Plugins/obs-outputs.so
|
||||||
|
|
||||||
|
# copy sparkle into the app
|
||||||
|
hr "Copying Sparkle.framework"
|
||||||
|
cp -r ../../sparkle/Sparkle.framework ./OBS.app/Contents/Frameworks/
|
||||||
|
install_name_tool -change @rpath/Sparkle.framework/Versions/A/Sparkle @executable_path/../Frameworks/Sparkle.framework/Versions/A/Sparkle ./OBS.app/Contents/MacOS/obs
|
||||||
|
|
||||||
# Copy Chromium embedded framework to app Frameworks directory
|
# Copy Chromium embedded framework to app Frameworks directory
|
||||||
hr "Copying Chromium Embedded Framework.framework"
|
hr "Copying Chromium Embedded Framework.framework"
|
||||||
sudo mkdir -p OBS.app/Contents/Frameworks
|
sudo mkdir -p OBS.app/Contents/Frameworks
|
||||||
sudo cp -r ../../cef_binary_${CEF_BUILD_VERSION}_macosx64/Release/Chromium\ Embedded\ Framework.framework OBS.app/Contents/Frameworks/
|
sudo cp -r ../../cef_binary_${CEF_BUILD_VERSION}_macosx64/Release/Chromium\ Embedded\ Framework.framework OBS.app/Contents/Frameworks/
|
||||||
sudo install_name_tool -change \
|
|
||||||
@rpath/Frameworks/Chromium\ Embedded\ Framework.framework/Chromium\ Embedded\ Framework \
|
|
||||||
../../Frameworks/Chromium\ Embedded\ Framework.framework/Chromium\ Embedded\ Framework \
|
|
||||||
OBS.app/Contents/Resources/obs-plugins/obs-browser.so
|
|
||||||
sudo install_name_tool -change \
|
|
||||||
@executable_path/../Frameworks/Chromium\ Embedded\ Framework.framework/Chromium\ Embedded\ Framework \
|
|
||||||
../../Frameworks/Chromium\ Embedded\ Framework.framework/Chromium\ Embedded\ Framework \
|
|
||||||
OBS.app/Contents/Resources/obs-plugins/obs-browser.so
|
|
||||||
sudo install_name_tool -change \
|
|
||||||
@rpath/Frameworks/Chromium\ Embedded\ Framework.framework/Chromium\ Embedded\ Framework \
|
|
||||||
../../Frameworks/Chromium\ Embedded\ Framework.framework/Chromium\ Embedded\ Framework \
|
|
||||||
OBS.app/Contents/Resources/obs-plugins/obs-browser-page
|
|
||||||
sudo install_name_tool -change \
|
|
||||||
@executable_path/../Frameworks/Chromium\ Embedded\ Framework.framework/Chromium\ Embedded\ Framework \
|
|
||||||
../../Frameworks/Chromium\ Embedded\ Framework.framework/Chromium\ Embedded\ Framework \
|
|
||||||
OBS.app/Contents/Resources/obs-plugins/obs-browser-page
|
|
||||||
|
|
||||||
# Package app
|
install_name_tool -change /usr/local/opt/qt/lib/QtGui.framework/Versions/5/QtGui @executable_path/../Frameworks/QtGui.framework/Versions/5/QtGui ./OBS.app/Contents/Plugins/obs-browser.so
|
||||||
hr "Generating .pkg"
|
install_name_tool -change /usr/local/opt/qt/lib/QtCore.framework/Versions/5/QtCore @executable_path/../Frameworks/QtCore.framework/Versions/5/QtCore ./OBS.app/Contents/Plugins/obs-browser.so
|
||||||
packagesbuild ../CI/install/osx/CMakeLists.pkgproj
|
install_name_tool -change /usr/local/opt/qt/lib/QtWidgets.framework/Versions/5/QtWidgets @executable_path/../Frameworks/QtWidgets.framework/Versions/5/QtWidgets ./OBS.app/Contents/Plugins/obs-browser.so
|
||||||
|
|
||||||
|
cp ../CI/install/osx/OBSPublicDSAKey.pem OBS.app/Contents/Resources
|
||||||
|
|
||||||
|
# edit plist
|
||||||
|
plutil -insert CFBundleVersion -string $GIT_TAG ./OBS.app/Contents/Info.plist
|
||||||
|
plutil -insert CFBundleShortVersionString -string $GIT_TAG ./OBS.app/Contents/Info.plist
|
||||||
|
plutil -insert OBSFeedsURL -string https://obsproject.com/osx_update/feeds.xml ./OBS.app/Contents/Info.plist
|
||||||
|
plutil -insert SUFeedURL -string https://obsproject.com/osx_update/stable/updates.xml ./OBS.app/Contents/Info.plist
|
||||||
|
plutil -insert SUPublicDSAKeyFile -string OBSPublicDSAKey.pem ./OBS.app/Contents/Info.plist
|
||||||
|
|
||||||
|
dmgbuild -s ../CI/install/osx/settings.json "OBS" obs.dmg
|
||||||
|
|
||||||
if [ -v "$TRAVIS" ]; then
|
if [ -v "$TRAVIS" ]; then
|
||||||
# Signing stuff
|
# Signing stuff
|
||||||
|
@ -70,12 +85,10 @@ if [ -v "$TRAVIS" ]; then
|
||||||
security import ./Certificates.p12 -k build.keychain -T /usr/bin/productsign -P ""
|
security import ./Certificates.p12 -k build.keychain -T /usr/bin/productsign -P ""
|
||||||
# macOS 10.12+
|
# macOS 10.12+
|
||||||
security set-key-partition-list -S apple-tool:,apple: -s -k mysecretpassword build.keychain
|
security set-key-partition-list -S apple-tool:,apple: -s -k mysecretpassword build.keychain
|
||||||
hr "Signing Package"
|
|
||||||
productsign --sign 2MMRE5MTB8 ./OBS.pkg ./$FILENAME
|
|
||||||
else
|
|
||||||
cp ./OBS.pkg ./$FILENAME
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
cp ./OBS.dmg ./$FILENAME
|
||||||
|
|
||||||
# Move to the folder that travis uses to upload artifacts from
|
# Move to the folder that travis uses to upload artifacts from
|
||||||
hr "Moving package to nightly folder for distribution"
|
hr "Moving package to nightly folder for distribution"
|
||||||
mkdir ../nightly
|
mkdir ../nightly
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
set -ex
|
set -ex
|
||||||
|
|
||||||
sudo add-apt-repository ppa:jonathonf/ffmpeg-3 -y
|
|
||||||
curl -L https://packagecloud.io/github/git-lfs/gpgkey | sudo apt-key add -
|
curl -L https://packagecloud.io/github/git-lfs/gpgkey | sudo apt-key add -
|
||||||
|
|
||||||
# gets us newer clang
|
# gets us newer clang
|
||||||
|
|
|
@ -16,6 +16,8 @@ else
|
||||||
/bin/bash -c "sudo xcode-select -s /Applications/Xcode_9.4.1.app/Contents/Developer"
|
/bin/bash -c "sudo xcode-select -s /Applications/Xcode_9.4.1.app/Contents/Developer"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
git fetch origin --tags
|
||||||
|
|
||||||
# Leave obs-studio folder
|
# Leave obs-studio folder
|
||||||
cd ../
|
cd ../
|
||||||
|
|
||||||
|
@ -28,10 +30,12 @@ sudo installer -pkg ./Packages.pkg -target /
|
||||||
brew update
|
brew update
|
||||||
|
|
||||||
#Base OBS Deps and ccache
|
#Base OBS Deps and ccache
|
||||||
brew install jack speexdsp ccache mbedtls clang-format
|
brew install jack speexdsp ccache mbedtls clang-format freetype fdk-aac
|
||||||
brew install https://gist.githubusercontent.com/DDRBoxman/b3956fab6073335a4bf151db0dcbd4ad/raw/ed1342a8a86793ea8c10d8b4d712a654da121ace/qt.rb
|
brew install https://gist.githubusercontent.com/DDRBoxman/b3956fab6073335a4bf151db0dcbd4ad/raw/ed1342a8a86793ea8c10d8b4d712a654da121ace/qt.rb
|
||||||
brew install https://gist.githubusercontent.com/DDRBoxman/4cada55c51803a2f963fa40ce55c9d3e/raw/572c67e908bfbc1bcb8c476ea77ea3935133f5b5/swig.rb
|
brew install https://gist.githubusercontent.com/DDRBoxman/4cada55c51803a2f963fa40ce55c9d3e/raw/572c67e908bfbc1bcb8c476ea77ea3935133f5b5/swig.rb
|
||||||
|
|
||||||
|
pip install dmgbuild
|
||||||
|
|
||||||
export PATH=/usr/local/opt/ccache/libexec:$PATH
|
export PATH=/usr/local/opt/ccache/libexec:$PATH
|
||||||
ccache -s || echo "CCache is not available."
|
ccache -s || echo "CCache is not available."
|
||||||
|
|
||||||
|
|
30
CI/install/osx/Info.plist
Normal file
30
CI/install/osx/Info.plist
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>CFBundleIconFile</key>
|
||||||
|
<string>obs.icns</string>
|
||||||
|
<key>CFBundleName</key>
|
||||||
|
<string>OBS</string>
|
||||||
|
<key>CFBundleGetInfoString</key>
|
||||||
|
<string>OBS - Free and Open Source Streaming/Recording Software</string>
|
||||||
|
<key>CFBundleExecutable</key>
|
||||||
|
<string>OBS</string>
|
||||||
|
<key>CFBundleIdentifier</key>
|
||||||
|
<string>com.obsproject.obs-studio</string>
|
||||||
|
<key>CFBundlePackageType</key>
|
||||||
|
<string>APPL</string>
|
||||||
|
<key>CFBundleSignature</key>
|
||||||
|
<string>????</string>
|
||||||
|
<key>LSMinimumSystemVersion</key>
|
||||||
|
<string>10.8.5</string>
|
||||||
|
<key>NSHighResolutionCapable</key>
|
||||||
|
<true/>
|
||||||
|
<key>LSAppNapIsDisabled</key>
|
||||||
|
<true/>
|
||||||
|
<key>NSCameraUsageDescription</key>
|
||||||
|
<string>OBS needs to access the camera to enable camera sources to work.</string>
|
||||||
|
<key>NSMicrophoneUsageDescription</key>
|
||||||
|
<string>OBS needs to access the microphone to enable audio input.</string>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
BIN
CI/install/osx/background.png
Normal file
BIN
CI/install/osx/background.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 13 KiB |
BIN
CI/install/osx/background.pxd/QuickLook/Icon.tiff
Normal file
BIN
CI/install/osx/background.pxd/QuickLook/Icon.tiff
Normal file
Binary file not shown.
BIN
CI/install/osx/background.pxd/QuickLook/Preview.tiff
Normal file
BIN
CI/install/osx/background.pxd/QuickLook/Preview.tiff
Normal file
Binary file not shown.
BIN
CI/install/osx/background.pxd/QuickLook/Thumbnail.tiff
Normal file
BIN
CI/install/osx/background.pxd/QuickLook/Thumbnail.tiff
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
CI/install/osx/background.pxd/metadata.info
Normal file
BIN
CI/install/osx/background.pxd/metadata.info
Normal file
Binary file not shown.
BIN
CI/install/osx/background.tiff
Normal file
BIN
CI/install/osx/background.tiff
Normal file
Binary file not shown.
BIN
CI/install/osx/background@2x.png
Normal file
BIN
CI/install/osx/background@2x.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 28 KiB |
1
CI/install/osx/buildDMG
Executable file
1
CI/install/osx/buildDMG
Executable file
|
@ -0,0 +1 @@
|
||||||
|
dmgbuild -s ./settings.json "OBS" obs.dmg
|
BIN
CI/install/osx/dylibBundler
Executable file
BIN
CI/install/osx/dylibBundler
Executable file
Binary file not shown.
1
CI/install/osx/makeRetinaBG
Executable file
1
CI/install/osx/makeRetinaBG
Executable file
|
@ -0,0 +1 @@
|
||||||
|
tiffutil -cathidpicheck background.png background@2x.png -out background.tiff
|
BIN
CI/install/osx/obs.icns
Normal file
BIN
CI/install/osx/obs.icns
Normal file
Binary file not shown.
67
CI/install/osx/packageApp.sh
Executable file
67
CI/install/osx/packageApp.sh
Executable file
|
@ -0,0 +1,67 @@
|
||||||
|
rm -rf ./OBS.app
|
||||||
|
|
||||||
|
mkdir OBS.app
|
||||||
|
mkdir OBS.app/Contents
|
||||||
|
mkdir OBS.app/Contents/MacOS
|
||||||
|
mkdir OBS.app/Contents/Plugins
|
||||||
|
mkdir OBS.app/Contents/Resources
|
||||||
|
|
||||||
|
cp -r rundir/RelWithDebInfo/bin/ ./OBS.app/Contents/MacOS
|
||||||
|
cp -r rundir/RelWithDebInfo/data ./OBS.app/Contents/Resources
|
||||||
|
cp ../CI/install/osx/obs.icns ./OBS.app/Contents/Resources
|
||||||
|
cp -r rundir/RelWithDebInfo/obs-plugins/ ./OBS.app/Contents/Plugins
|
||||||
|
cp ../CI/install/osx/Info.plist ./OBS.app/Contents
|
||||||
|
|
||||||
|
../CI/install/osx/dylibBundler -b -cd -d ./OBS.app/Contents/Frameworks -p @executable_path/../Frameworks/ \
|
||||||
|
-s ./OBS.app/Contents/MacOS \
|
||||||
|
-s /usr/local/opt/mbedtls/lib/ \
|
||||||
|
-x ./OBS.app/Contents/Plugins/coreaudio-encoder.so \
|
||||||
|
-x ./OBS.app/Contents/Plugins/decklink-ouput-ui.so \
|
||||||
|
-x ./OBS.app/Contents/Plugins/frontend-tools.so \
|
||||||
|
-x ./OBS.app/Contents/Plugins/image-source.so \
|
||||||
|
-x ./OBS.app/Contents/Plugins/linux-jack.so \
|
||||||
|
-x ./OBS.app/Contents/Plugins/mac-avcapture.so \
|
||||||
|
-x ./OBS.app/Contents/Plugins/mac-capture.so \
|
||||||
|
-x ./OBS.app/Contents/Plugins/mac-decklink.so \
|
||||||
|
-x ./OBS.app/Contents/Plugins/mac-syphon.so \
|
||||||
|
-x ./OBS.app/Contents/Plugins/mac-vth264.so \
|
||||||
|
-x ./OBS.app/Contents/Plugins/obs-browser.so \
|
||||||
|
-x ./OBS.app/Contents/Plugins/obs-browser-page \
|
||||||
|
-x ./OBS.app/Contents/Plugins/obs-ffmpeg.so \
|
||||||
|
-x ./OBS.app/Contents/Plugins/obs-filters.so \
|
||||||
|
-x ./OBS.app/Contents/Plugins/obs-transitions.so \
|
||||||
|
-x ./OBS.app/Contents/Plugins/obs-vst.so \
|
||||||
|
-x ./OBS.app/Contents/Plugins/rtmp-services.so \
|
||||||
|
-x ./OBS.app/Contents/MacOS/obs \
|
||||||
|
-x ./OBS.app/Contents/MacOS/obs-ffmpeg-mux \
|
||||||
|
-x ./OBS.app/Contents/MacOS/obslua.so \
|
||||||
|
-x ./OBS.app/Contents/MacOS/_obspython.so \
|
||||||
|
-x ./OBS.app/Contents/Plugins/obs-x264.so \
|
||||||
|
-x ./OBS.app/Contents/Plugins/text-freetype2.so \
|
||||||
|
-x ./OBS.app/Contents/Plugins/obs-libfdk.so
|
||||||
|
# -x ./OBS.app/Contents/Plugins/obs-outputs.so \
|
||||||
|
|
||||||
|
/usr/local/Cellar/qt/5.10.1/bin/macdeployqt ./OBS.app
|
||||||
|
|
||||||
|
mv ./OBS.app/Contents/MacOS/libobs-opengl.so ./OBS.app/Contents/Frameworks
|
||||||
|
|
||||||
|
# put qt network in here becasuse streamdeck uses it
|
||||||
|
cp -r /usr/local/opt/qt/lib/QtNetwork.framework ./OBS.app/Contents/Frameworks
|
||||||
|
chmod +w ./OBS.app/Contents/Frameworks/QtNetwork.framework/Versions/5/QtNetwork
|
||||||
|
install_name_tool -change /usr/local/Cellar/qt/5.10.1/lib/QtCore.framework/Versions/5/QtCore @executable_path/../Frameworks/QtCore.framework/Versions/5/QtCore ./OBS.app/Contents/Frameworks/QtNetwork.framework/Versions/5/QtNetwork
|
||||||
|
|
||||||
|
# decklink ui qt
|
||||||
|
install_name_tool -change /usr/local/opt/qt/lib/QtGui.framework/Versions/5/QtGui @executable_path/../Frameworks/QtGui.framework/Versions/5/QtGui ./OBS.app/Contents/Plugins/decklink-ouput-ui.so
|
||||||
|
install_name_tool -change /usr/local/opt/qt/lib/QtCore.framework/Versions/5/QtCore @executable_path/../Frameworks/QtCore.framework/Versions/5/QtCore ./OBS.app/Contents/Plugins/decklink-ouput-ui.so
|
||||||
|
install_name_tool -change /usr/local/opt/qt/lib/QtWidgets.framework/Versions/5/QtWidgets @executable_path/../Frameworks/QtWidgets.framework/Versions/5/QtWidgets ./OBS.app/Contents/Plugins/decklink-ouput-ui.so
|
||||||
|
|
||||||
|
# frontend tools qt
|
||||||
|
install_name_tool -change /usr/local/opt/qt/lib/QtGui.framework/Versions/5/QtGui @executable_path/../Frameworks/QtGui.framework/Versions/5/QtGui ./OBS.app/Contents/Plugins/frontend-tools.so
|
||||||
|
install_name_tool -change /usr/local/opt/qt/lib/QtCore.framework/Versions/5/QtCore @executable_path/../Frameworks/QtCore.framework/Versions/5/QtCore ./OBS.app/Contents/Plugins/frontend-tools.so
|
||||||
|
install_name_tool -change /usr/local/opt/qt/lib/QtWidgets.framework/Versions/5/QtWidgets @executable_path/../Frameworks/QtWidgets.framework/Versions/5/QtWidgets ./OBS.app/Contents/Plugins/frontend-tools.so
|
||||||
|
|
||||||
|
# vst qt
|
||||||
|
install_name_tool -change /usr/local/opt/qt/lib/QtGui.framework/Versions/5/QtGui @executable_path/../Frameworks/QtGui.framework/Versions/5/QtGui ./OBS.app/Contents/Plugins/obs-vst.so
|
||||||
|
install_name_tool -change /usr/local/opt/qt/lib/QtCore.framework/Versions/5/QtCore @executable_path/../Frameworks/QtCore.framework/Versions/5/QtCore ./OBS.app/Contents/Plugins/obs-vst.so
|
||||||
|
install_name_tool -change /usr/local/opt/qt/lib/QtWidgets.framework/Versions/5/QtWidgets @executable_path/../Frameworks/QtWidgets.framework/Versions/5/QtWidgets ./OBS.app/Contents/Plugins/obs-vst.so
|
||||||
|
install_name_tool -change /usr/local/opt/qt/lib/QtMacExtras.framework/Versions/5/QtMacExtras @executable_path/../Frameworks/QtMacExtras.framework/Versions/5/QtMacExtras ./OBS.app/Contents/Plugins/obs-vst.so
|
13
CI/install/osx/settings.json
Normal file
13
CI/install/osx/settings.json
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
{
|
||||||
|
"title": "OBS",
|
||||||
|
"background": "../CI/install/osx/background.tiff",
|
||||||
|
"format": "UDZO",
|
||||||
|
"compression-level": 9,
|
||||||
|
"window": { "position": { "x": 100, "y": 100 },
|
||||||
|
"size": { "width": 540, "height": 380 } },
|
||||||
|
"contents": [
|
||||||
|
{ "x": 120, "y": 180, "type": "file",
|
||||||
|
"path": "./OBS.app" },
|
||||||
|
{ "x": 420, "y": 180, "type": "link", "path": "/Applications" }
|
||||||
|
]
|
||||||
|
}
|
|
@ -373,14 +373,6 @@ if (APPLE)
|
||||||
target_link_libraries(obs
|
target_link_libraries(obs
|
||||||
Qt5::MacExtras)
|
Qt5::MacExtras)
|
||||||
set_target_properties(obs PROPERTIES LINK_FLAGS "-pagezero_size 10000 -image_base 100000000")
|
set_target_properties(obs PROPERTIES LINK_FLAGS "-pagezero_size 10000 -image_base 100000000")
|
||||||
set_property(
|
|
||||||
TARGET obs
|
|
||||||
APPEND
|
|
||||||
PROPERTY INSTALL_RPATH
|
|
||||||
"/usr/local/Cellar/python3/3.6.4_2/Frameworks/Python.framework/Versions/3.6/lib/"
|
|
||||||
"/Library/Frameworks/Python.framework/Versions/3.6/lib/"
|
|
||||||
"/opt/local/Library/Frameworks/Python.framework/Versions/3.6/lib/"
|
|
||||||
)
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
define_graphic_modules(obs)
|
define_graphic_modules(obs)
|
||||||
|
|
|
@ -216,7 +216,8 @@ void TwitchAuth::LoadUI()
|
||||||
chat->SetWidget(browser);
|
chat->SetWidget(browser);
|
||||||
cef->add_force_popup_url(moderation_tools_url, chat.data());
|
cef->add_force_popup_url(moderation_tools_url, chat.data());
|
||||||
|
|
||||||
script = bttv_script;
|
script = "localStorage.setItem('twilight.theme', 1);";
|
||||||
|
script += bttv_script;
|
||||||
script += ffz_script;
|
script += ffz_script;
|
||||||
browser->setStartupScript(script);
|
browser->setStartupScript(script);
|
||||||
|
|
||||||
|
|
|
@ -3685,19 +3685,19 @@
|
||||||
<item row="0" column="1">
|
<item row="0" column="1">
|
||||||
<widget class="QComboBox" name="sampleRate">
|
<widget class="QComboBox" name="sampleRate">
|
||||||
<property name="currentText">
|
<property name="currentText">
|
||||||
<string notr="true">44.1khz</string>
|
<string notr="true">44.1 kHz</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="currentIndex">
|
<property name="currentIndex">
|
||||||
<number>0</number>
|
<number>0</number>
|
||||||
</property>
|
</property>
|
||||||
<item>
|
<item>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>44.1khz</string>
|
<string>44.1 kHz</string>
|
||||||
</property>
|
</property>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>48khz</string>
|
<string>48 kHz</string>
|
||||||
</property>
|
</property>
|
||||||
</item>
|
</item>
|
||||||
</widget>
|
</widget>
|
||||||
|
|
|
@ -126,9 +126,16 @@ static std::string GetWindowTitle(size_t i)
|
||||||
if (status >= Success && name != nullptr) {
|
if (status >= Success && name != nullptr) {
|
||||||
std::string str(name);
|
std::string str(name);
|
||||||
windowTitle = str;
|
windowTitle = str;
|
||||||
}
|
|
||||||
|
|
||||||
XFree(name);
|
XFree(name);
|
||||||
|
} else {
|
||||||
|
XTextProperty xtp_new_name;
|
||||||
|
if (XGetWMName(disp(), w, &xtp_new_name) != 0 &&
|
||||||
|
xtp_new_name.value != nullptr) {
|
||||||
|
std::string str((const char *)xtp_new_name.value);
|
||||||
|
windowTitle = str;
|
||||||
|
XFree(xtp_new_name.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return windowTitle;
|
return windowTitle;
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,11 +28,29 @@
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
|
bool isInBundle()
|
||||||
|
{
|
||||||
|
NSRunningApplication *app = [NSRunningApplication currentApplication];
|
||||||
|
return [app bundleIdentifier] != nil;
|
||||||
|
}
|
||||||
|
|
||||||
bool GetDataFilePath(const char *data, string &output)
|
bool GetDataFilePath(const char *data, string &output)
|
||||||
{
|
{
|
||||||
|
if (isInBundle()) {
|
||||||
|
NSRunningApplication *app =
|
||||||
|
[NSRunningApplication currentApplication];
|
||||||
|
NSURL *bundleURL = [app bundleURL];
|
||||||
|
NSString *path = [NSString
|
||||||
|
stringWithFormat:@"Contents/Resources/data/obs-studio/%@",
|
||||||
|
[NSString stringWithUTF8String:data]];
|
||||||
|
NSURL *dataURL = [bundleURL URLByAppendingPathComponent:path];
|
||||||
|
output = [[dataURL path] UTF8String];
|
||||||
|
} else {
|
||||||
stringstream str;
|
stringstream str;
|
||||||
str << OBS_DATA_PATH "/obs-studio/" << data;
|
str << OBS_DATA_PATH "/obs-studio/" << data;
|
||||||
output = str.str();
|
output = str.str();
|
||||||
|
}
|
||||||
|
|
||||||
return !access(output.c_str(), R_OK);
|
return !access(output.c_str(), R_OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1820,7 +1820,7 @@ void WidgetInfo::ControlChanged()
|
||||||
break;
|
break;
|
||||||
case OBS_PROPERTY_GROUP:
|
case OBS_PROPERTY_GROUP:
|
||||||
GroupChanged(setting);
|
GroupChanged(setting);
|
||||||
return;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (view->callback && !view->deferUpdate)
|
if (view->callback && !view->deferUpdate)
|
||||||
|
|
|
@ -417,6 +417,8 @@ void AutoConfigStreamPage::on_connectAccount_clicked()
|
||||||
#ifdef BROWSER_AVAILABLE
|
#ifdef BROWSER_AVAILABLE
|
||||||
std::string service = QT_TO_UTF8(ui->service->currentText());
|
std::string service = QT_TO_UTF8(ui->service->currentText());
|
||||||
|
|
||||||
|
OAuth::DeleteCookies(service);
|
||||||
|
|
||||||
auth = OAuthStreamKey::Login(this, service);
|
auth = OAuthStreamKey::Login(this, service);
|
||||||
if (!!auth)
|
if (!!auth)
|
||||||
OnAuthConnected();
|
OnAuthConnected();
|
||||||
|
|
|
@ -59,6 +59,10 @@ OBSBasicInteraction::OBSBasicInteraction(QWidget *parent, OBSSource source_)
|
||||||
const char *name = obs_source_get_name(source);
|
const char *name = obs_source_get_name(source);
|
||||||
setWindowTitle(QTStr("Basic.InteractionWindow").arg(QT_UTF8(name)));
|
setWindowTitle(QTStr("Basic.InteractionWindow").arg(QT_UTF8(name)));
|
||||||
|
|
||||||
|
Qt::WindowFlags flags = windowFlags();
|
||||||
|
Qt::WindowFlags helpFlag = Qt::WindowContextHelpButtonHint;
|
||||||
|
setWindowFlags(flags & (~helpFlag));
|
||||||
|
|
||||||
auto addDrawCallback = [this]() {
|
auto addDrawCallback = [this]() {
|
||||||
obs_display_add_draw_callback(ui->preview->GetDisplay(),
|
obs_display_add_draw_callback(ui->preview->GetDisplay(),
|
||||||
OBSBasicInteraction::DrawPreview,
|
OBSBasicInteraction::DrawPreview,
|
||||||
|
|
|
@ -643,6 +643,7 @@ void SimpleOutput::UpdateRecordingSettings()
|
||||||
} else if (videoEncoder == SIMPLE_ENCODER_NVENC) {
|
} else if (videoEncoder == SIMPLE_ENCODER_NVENC) {
|
||||||
UpdateRecordingSettings_nvenc(crf);
|
UpdateRecordingSettings_nvenc(crf);
|
||||||
}
|
}
|
||||||
|
UpdateRecordingAudioSettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void SimpleOutput::SetupOutputs()
|
inline void SimpleOutput::SetupOutputs()
|
||||||
|
|
|
@ -88,6 +88,38 @@ static bool SceneCollectionExists(const char *findName)
|
||||||
return found;
|
return found;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool GetUnusedSceneCollectionFile(std::string &name, std::string &file)
|
||||||
|
{
|
||||||
|
char path[512];
|
||||||
|
size_t len;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (!GetFileSafeName(name.c_str(), file)) {
|
||||||
|
blog(LOG_WARNING, "Failed to create safe file name for '%s'",
|
||||||
|
name.c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = GetConfigPath(path, sizeof(path), "obs-studio/basic/scenes/");
|
||||||
|
if (ret <= 0) {
|
||||||
|
blog(LOG_WARNING, "Failed to get scene collection config path");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
len = file.size();
|
||||||
|
file.insert(0, path);
|
||||||
|
|
||||||
|
if (!GetClosestUnusedFileName(file, "json")) {
|
||||||
|
blog(LOG_WARNING, "Failed to get closest file name for %s",
|
||||||
|
file.c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
file.erase(file.size() - 5, 5);
|
||||||
|
file.erase(0, file.size() - len);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static bool GetSceneCollectionName(QWidget *parent, std::string &name,
|
static bool GetSceneCollectionName(QWidget *parent, std::string &name,
|
||||||
std::string &file,
|
std::string &file,
|
||||||
const char *oldName = nullptr)
|
const char *oldName = nullptr)
|
||||||
|
@ -95,9 +127,6 @@ static bool GetSceneCollectionName(QWidget *parent, std::string &name,
|
||||||
bool rename = oldName != nullptr;
|
bool rename = oldName != nullptr;
|
||||||
const char *title;
|
const char *title;
|
||||||
const char *text;
|
const char *text;
|
||||||
char path[512];
|
|
||||||
size_t len;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
if (rename) {
|
if (rename) {
|
||||||
title = Str("Basic.Main.RenameSceneCollection.Title");
|
title = Str("Basic.Main.RenameSceneCollection.Title");
|
||||||
|
@ -128,29 +157,10 @@ static bool GetSceneCollectionName(QWidget *parent, std::string &name,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!GetFileSafeName(name.c_str(), file)) {
|
if (!GetUnusedSceneCollectionFile(name, file)) {
|
||||||
blog(LOG_WARNING, "Failed to create safe file name for '%s'",
|
|
||||||
name.c_str());
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = GetConfigPath(path, sizeof(path), "obs-studio/basic/scenes/");
|
|
||||||
if (ret <= 0) {
|
|
||||||
blog(LOG_WARNING, "Failed to get scene collection config path");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
len = file.size();
|
|
||||||
file.insert(0, path);
|
|
||||||
|
|
||||||
if (!GetClosestUnusedFileName(file, "json")) {
|
|
||||||
blog(LOG_WARNING, "Failed to get closest file name for %s",
|
|
||||||
file.c_str());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
file.erase(file.size() - 5, 5);
|
|
||||||
file.erase(0, file.size() - len);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -166,6 +176,10 @@ bool OBSBasic::AddSceneCollection(bool create_new, const QString &qname)
|
||||||
name = QT_TO_UTF8(qname);
|
name = QT_TO_UTF8(qname);
|
||||||
if (SceneCollectionExists(name.c_str()))
|
if (SceneCollectionExists(name.c_str()))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
if (!GetUnusedSceneCollectionFile(name, file)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SaveProjectNow();
|
SaveProjectNow();
|
||||||
|
|
|
@ -466,6 +466,8 @@ void OBSBasicSettings::on_connectAccount_clicked()
|
||||||
#ifdef BROWSER_AVAILABLE
|
#ifdef BROWSER_AVAILABLE
|
||||||
std::string service = QT_TO_UTF8(ui->service->currentText());
|
std::string service = QT_TO_UTF8(ui->service->currentText());
|
||||||
|
|
||||||
|
OAuth::DeleteCookies(service);
|
||||||
|
|
||||||
auth = OAuthStreamKey::Login(this, service);
|
auth = OAuthStreamKey::Login(this, service);
|
||||||
if (!!auth)
|
if (!!auth)
|
||||||
OnAuthConnected();
|
OnAuthConnected();
|
||||||
|
|
|
@ -2189,9 +2189,9 @@ void OBSBasicSettings::LoadAudioSettings()
|
||||||
|
|
||||||
const char *str;
|
const char *str;
|
||||||
if (sampleRate == 48000)
|
if (sampleRate == 48000)
|
||||||
str = "48khz";
|
str = "48 kHz";
|
||||||
else
|
else
|
||||||
str = "44.1khz";
|
str = "44.1 kHz";
|
||||||
|
|
||||||
int sampleRateIdx = ui->sampleRate->findText(str);
|
int sampleRateIdx = ui->sampleRate->findText(str);
|
||||||
if (sampleRateIdx != -1)
|
if (sampleRateIdx != -1)
|
||||||
|
@ -3253,7 +3253,7 @@ void OBSBasicSettings::SaveAudioSettings()
|
||||||
}
|
}
|
||||||
|
|
||||||
int sampleRate = 44100;
|
int sampleRate = 44100;
|
||||||
if (sampleRateStr == "48khz")
|
if (sampleRateStr == "48 kHz")
|
||||||
sampleRate = 48000;
|
sampleRate = 48000;
|
||||||
|
|
||||||
if (WidgetChanged(ui->sampleRate))
|
if (WidgetChanged(ui->sampleRate))
|
||||||
|
|
|
@ -533,6 +533,24 @@ void OBSBasic::AddExtraBrowserDock(const QString &title, const QString &url,
|
||||||
|
|
||||||
dock->SetWidget(browser);
|
dock->SetWidget(browser);
|
||||||
|
|
||||||
|
/* Add support for Twitch Dashboard panels */
|
||||||
|
if (url.contains("twitch.tv/popout") &&
|
||||||
|
url.contains("dashboard/live")) {
|
||||||
|
QRegularExpression re("twitch.tv\/popout\/([^/]+)\/");
|
||||||
|
QRegularExpressionMatch match = re.match(url);
|
||||||
|
QString username = match.captured(1);
|
||||||
|
if (username.length() > 0) {
|
||||||
|
std::string script;
|
||||||
|
script =
|
||||||
|
"Object.defineProperty(document, 'referrer', { get: () => '";
|
||||||
|
script += "https://twitch.tv/";
|
||||||
|
script += QT_TO_UTF8(username);
|
||||||
|
script += "/dashboard/live";
|
||||||
|
script += "'});";
|
||||||
|
browser->setStartupScript(script);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
addDockWidget(Qt::RightDockWidgetArea, dock);
|
addDockWidget(Qt::RightDockWidgetArea, dock);
|
||||||
|
|
||||||
if (firstCreate) {
|
if (firstCreate) {
|
||||||
|
|
|
@ -653,6 +653,9 @@ void OBSProjector::OBSRender(void *data, uint32_t cx, uint32_t cy)
|
||||||
source = curSource;
|
source = curSource;
|
||||||
window->source = source;
|
window->source = source;
|
||||||
}
|
}
|
||||||
|
} else if (window->type == ProjectorType::Preview &&
|
||||||
|
!main->IsPreviewProgramMode()) {
|
||||||
|
window->source = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (source)
|
if (source)
|
||||||
|
|
|
@ -61,7 +61,7 @@ if(NOT UNIX_STRUCTURE)
|
||||||
set(OBS_INSTALL_PREFIX "")
|
set(OBS_INSTALL_PREFIX "")
|
||||||
set(OBS_RELATIVE_PREFIX "../")
|
set(OBS_RELATIVE_PREFIX "../")
|
||||||
|
|
||||||
set(OBS_SCRIPT_PLUGIN_DESTINATION "${OBS_DATA_DESTINATION}/obs-scripting/${_lib_suffix}bit")
|
set(OBS_SCRIPT_PLUGIN_DESTINATION "${OBS_DATA_DESTINATION}/obs-scripting")
|
||||||
else()
|
else()
|
||||||
set(OBS_EXECUTABLE_DESTINATION "bin/${_lib_suffix}bit")
|
set(OBS_EXECUTABLE_DESTINATION "bin/${_lib_suffix}bit")
|
||||||
set(OBS_EXECUTABLE32_DESTINATION "bin/32bit")
|
set(OBS_EXECUTABLE32_DESTINATION "bin/32bit")
|
||||||
|
|
6
deps/media-playback/media-playback/media.c
vendored
6
deps/media-playback/media-playback/media.c
vendored
|
@ -139,7 +139,7 @@ static int mp_media_next_packet(mp_media_t *media)
|
||||||
|
|
||||||
int ret = av_read_frame(media->fmt, &pkt);
|
int ret = av_read_frame(media->fmt, &pkt);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
if (ret != AVERROR_EOF)
|
if (ret != AVERROR_EOF && ret != AVERROR_EXIT)
|
||||||
blog(LOG_WARNING, "MP: av_read_frame failed: %s (%d)",
|
blog(LOG_WARNING, "MP: av_read_frame failed: %s (%d)",
|
||||||
av_err2str(ret), ret);
|
av_err2str(ret), ret);
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -230,7 +230,7 @@ static bool mp_media_prepare_frames(mp_media_t *m)
|
||||||
while (!mp_media_ready_to_start(m)) {
|
while (!mp_media_ready_to_start(m)) {
|
||||||
if (!m->eof) {
|
if (!m->eof) {
|
||||||
int ret = mp_media_next_packet(m);
|
int ret = mp_media_next_packet(m);
|
||||||
if (ret == AVERROR_EOF)
|
if (ret == AVERROR_EOF || ret == AVERROR_EXIT)
|
||||||
m->eof = true;
|
m->eof = true;
|
||||||
else if (ret < 0)
|
else if (ret < 0)
|
||||||
return false;
|
return false;
|
||||||
|
@ -577,8 +577,10 @@ static bool init_avformat(mp_media_t *m)
|
||||||
av_dict_set_int(&opts, "buffer_size", m->buffering, 0);
|
av_dict_set_int(&opts, "buffer_size", m->buffering, 0);
|
||||||
|
|
||||||
m->fmt = avformat_alloc_context();
|
m->fmt = avformat_alloc_context();
|
||||||
|
if (!m->is_local_file) {
|
||||||
m->fmt->interrupt_callback.callback = interrupt_callback;
|
m->fmt->interrupt_callback.callback = interrupt_callback;
|
||||||
m->fmt->interrupt_callback.opaque = m;
|
m->fmt->interrupt_callback.opaque = m;
|
||||||
|
}
|
||||||
|
|
||||||
int ret = avformat_open_input(&m->fmt, m->path, format,
|
int ret = avformat_open_input(&m->fmt, m->path, format,
|
||||||
opts ? &opts : NULL);
|
opts ? &opts : NULL);
|
||||||
|
|
5
deps/obs-scripting/CMakeLists.txt
vendored
5
deps/obs-scripting/CMakeLists.txt
vendored
|
@ -12,6 +12,11 @@ if(MSVC)
|
||||||
w32-pthreads)
|
w32-pthreads)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(APPLE)
|
||||||
|
set(obs-scripting_PLATFORM_DEPS
|
||||||
|
objc)
|
||||||
|
endif()
|
||||||
|
|
||||||
option(DISABLE_LUA "Disable Lua scripting support" OFF)
|
option(DISABLE_LUA "Disable Lua scripting support" OFF)
|
||||||
option(DISABLE_PYTHON "Disable Python scripting support" OFF)
|
option(DISABLE_PYTHON "Disable Python scripting support" OFF)
|
||||||
|
|
||||||
|
|
29
deps/obs-scripting/obs-scripting-lua.c
vendored
29
deps/obs-scripting/obs-scripting-lua.c
vendored
|
@ -43,7 +43,8 @@ static const char *startup_script_template = "\
|
||||||
for val in pairs(package.preload) do\n\
|
for val in pairs(package.preload) do\n\
|
||||||
package.preload[val] = nil\n\
|
package.preload[val] = nil\n\
|
||||||
end\n\
|
end\n\
|
||||||
package.cpath = package.cpath .. \";\" .. \"%s\" .. \"/?." SO_EXT "\"\n\
|
package.cpath = package.cpath .. \";\" .. \"%s/Contents/MacOS/?.so\" .. \";\" .. \"%s\" .. \"/?." SO_EXT
|
||||||
|
"\"\n\
|
||||||
require \"obslua\"\n";
|
require \"obslua\"\n";
|
||||||
|
|
||||||
static const char *get_script_path_func = "\
|
static const char *get_script_path_func = "\
|
||||||
|
@ -1310,7 +1311,31 @@ void obs_lua_load(void)
|
||||||
/* ---------------------------------------------- */
|
/* ---------------------------------------------- */
|
||||||
/* Initialize Lua startup script */
|
/* Initialize Lua startup script */
|
||||||
|
|
||||||
dstr_printf(&tmp, startup_script_template, SCRIPT_DIR);
|
char *bundlePath = "./";
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
Class nsRunningApplication = objc_lookUpClass("NSRunningApplication");
|
||||||
|
SEL currentAppSel = sel_getUid("currentApplication");
|
||||||
|
|
||||||
|
typedef id (*running_app_func)(Class, SEL);
|
||||||
|
running_app_func operatingSystemName = (running_app_func)objc_msgSend;
|
||||||
|
id app = operatingSystemName(nsRunningApplication, currentAppSel);
|
||||||
|
|
||||||
|
typedef id (*bundle_url_func)(id, SEL);
|
||||||
|
bundle_url_func bundleURL = (bundle_url_func)objc_msgSend;
|
||||||
|
id url = bundleURL(app, sel_getUid("bundleURL"));
|
||||||
|
|
||||||
|
typedef id (*url_path_func)(id, SEL);
|
||||||
|
url_path_func urlPath = (url_path_func)objc_msgSend;
|
||||||
|
|
||||||
|
id path = urlPath(url, sel_getUid("path"));
|
||||||
|
|
||||||
|
typedef id (*string_func)(id, SEL);
|
||||||
|
string_func utf8String = (string_func)objc_msgSend;
|
||||||
|
bundlePath = (char *)utf8String(path, sel_registerName("UTF8String"));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
dstr_printf(&tmp, startup_script_template, bundlePath, SCRIPT_DIR);
|
||||||
startup_script = tmp.array;
|
startup_script = tmp.array;
|
||||||
|
|
||||||
dstr_free(&dep_paths);
|
dstr_free(&dep_paths);
|
||||||
|
|
|
@ -32,6 +32,12 @@
|
||||||
#define SO_EXT ".dylib"
|
#define SO_EXT ".dylib"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
#define PYTHON_LIB_SUBDIR "lib/"
|
||||||
|
#else
|
||||||
|
#define PYTHON_LIB_SUBDIR ""
|
||||||
|
#endif
|
||||||
|
|
||||||
bool import_python(const char *python_path)
|
bool import_python(const char *python_path)
|
||||||
{
|
{
|
||||||
struct dstr lib_path;
|
struct dstr lib_path;
|
||||||
|
@ -44,7 +50,7 @@ bool import_python(const char *python_path)
|
||||||
dstr_init_copy(&lib_path, python_path);
|
dstr_init_copy(&lib_path, python_path);
|
||||||
dstr_replace(&lib_path, "\\", "/");
|
dstr_replace(&lib_path, "\\", "/");
|
||||||
if (!dstr_is_empty(&lib_path)) {
|
if (!dstr_is_empty(&lib_path)) {
|
||||||
dstr_cat(&lib_path, "/");
|
dstr_cat(&lib_path, "/" PYTHON_LIB_SUBDIR);
|
||||||
}
|
}
|
||||||
dstr_cat(&lib_path, PYTHON_LIB SO_EXT);
|
dstr_cat(&lib_path, PYTHON_LIB SO_EXT);
|
||||||
|
|
||||||
|
|
7
deps/obs-scripting/obs-scripting-python.c
vendored
7
deps/obs-scripting/obs-scripting-python.c
vendored
|
@ -1651,6 +1651,13 @@ bool obs_scripting_load_python(const char *python_path)
|
||||||
|
|
||||||
add_to_python_path(SCRIPT_DIR);
|
add_to_python_path(SCRIPT_DIR);
|
||||||
|
|
||||||
|
#if __APPLE__
|
||||||
|
char *exec_path = os_get_executable_path_ptr("");
|
||||||
|
if (exec_path)
|
||||||
|
add_to_python_path(exec_path);
|
||||||
|
bfree(exec_path);
|
||||||
|
#endif
|
||||||
|
|
||||||
py_obspython = PyImport_ImportModule("obspython");
|
py_obspython = PyImport_ImportModule("obspython");
|
||||||
bool success = !py_error();
|
bool success = !py_error();
|
||||||
if (!success) {
|
if (!success) {
|
||||||
|
|
14
deps/obs-scripting/obspython/CMakeLists.txt
vendored
14
deps/obs-scripting/obspython/CMakeLists.txt
vendored
|
@ -42,7 +42,12 @@ if(CMAKE_VERSION VERSION_GREATER 3.7.2)
|
||||||
else()
|
else()
|
||||||
SWIG_ADD_MODULE(obspython python obspython.i ../cstrcache.cpp ../cstrcache.h)
|
SWIG_ADD_MODULE(obspython python obspython.i ../cstrcache.cpp ../cstrcache.h)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
IF(APPLE)
|
||||||
|
SWIG_LINK_LIBRARIES(obspython obs-scripting libobs)
|
||||||
|
ELSE()
|
||||||
SWIG_LINK_LIBRARIES(obspython obs-scripting libobs ${PYTHON_LIBRARIES})
|
SWIG_LINK_LIBRARIES(obspython obs-scripting libobs ${PYTHON_LIBRARIES})
|
||||||
|
ENDIF()
|
||||||
|
|
||||||
function(install_plugin_bin_swig target additional_target)
|
function(install_plugin_bin_swig target additional_target)
|
||||||
if(APPLE)
|
if(APPLE)
|
||||||
|
@ -57,14 +62,7 @@ function(install_plugin_bin_swig target additional_target)
|
||||||
PREFIX "")
|
PREFIX "")
|
||||||
|
|
||||||
if (APPLE)
|
if (APPLE)
|
||||||
set_property(
|
SET_TARGET_PROPERTIES(${additional_target} PROPERTIES LINK_FLAGS "-undefined dynamic_lookup")
|
||||||
TARGET ${additional_target}
|
|
||||||
APPEND
|
|
||||||
PROPERTY INSTALL_RPATH
|
|
||||||
"/usr/local/Cellar/python3/3.6.4_2/Frameworks/Python.framework/Versions/3.6/lib/"
|
|
||||||
"/Library/Frameworks/Python.framework/Versions/3.6/lib/"
|
|
||||||
"/opt/local/Library/Frameworks/Python.framework/Versions/3.6/lib/"
|
|
||||||
)
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/obspython.py"
|
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/obspython.py"
|
||||||
|
|
|
@ -27,5 +27,14 @@ else
|
||||||
CLANG_FORMAT=clang-format
|
CLANG_FORMAT=clang-format
|
||||||
fi
|
fi
|
||||||
|
|
||||||
find . -type d \( -path ./deps -o -path ./cmake -o -path ./plugins/decklink/win -o -path ./plugins/decklink/mac -o -path ./plugins/decklink/linux -o -path ./build \) -prune -type f -o -name '*.h' -or -name '*.hpp' -or -name '*.m' -or -name '*.mm' -or -name '*.c' -or -name '*.cpp' \
|
find . -type d \( -path ./deps \
|
||||||
|
-o -path ./cmake \
|
||||||
|
-o -path ./plugins/decklink/win \
|
||||||
|
-o -path ./plugins/decklink/mac \
|
||||||
|
-o -path ./plugins/decklink/linux \
|
||||||
|
-o -path ./plugins/enc-amf \
|
||||||
|
-o -path ./plugins/mac-syphon/syphon-framework \
|
||||||
|
-o -path ./plugins/obs-outputs/ftl-sdk \
|
||||||
|
-o -path ./plugins/obs-vst \
|
||||||
|
-o -path ./build \) -prune -type f -o -name '*.h' -or -name '*.hpp' -or -name '*.m' -or -name '*.mm' -or -name '*.c' -or -name '*.cpp' \
|
||||||
| xargs -I{} -P ${NPROC} ${CLANG_FORMAT} -i -style=file -fallback-style=none {}
|
| xargs -I{} -P ${NPROC} ${CLANG_FORMAT} -i -style=file -fallback-style=none {}
|
||||||
|
|
|
@ -178,10 +178,13 @@ void gs_vertex_shader::Rebuild(ID3D11Device *dev)
|
||||||
if (FAILED(hr))
|
if (FAILED(hr))
|
||||||
throw HRError("Failed to create vertex shader", hr);
|
throw HRError("Failed to create vertex shader", hr);
|
||||||
|
|
||||||
hr = dev->CreateInputLayout(layoutData.data(), (UINT)layoutData.size(),
|
const UINT layoutSize = (UINT)layoutData.size();
|
||||||
|
if (layoutSize > 0) {
|
||||||
|
hr = dev->CreateInputLayout(layoutData.data(), layoutSize,
|
||||||
data.data(), data.size(), &layout);
|
data.data(), data.size(), &layout);
|
||||||
if (FAILED(hr))
|
if (FAILED(hr))
|
||||||
throw HRError("Failed to create input layout", hr);
|
throw HRError("Failed to create input layout", hr);
|
||||||
|
}
|
||||||
|
|
||||||
if (constantSize) {
|
if (constantSize) {
|
||||||
hr = dev->CreateBuffer(&bd, NULL, &constants);
|
hr = dev->CreateBuffer(&bd, NULL, &constants);
|
||||||
|
|
|
@ -796,6 +796,53 @@ bool device_enum_adapters(bool (*callback)(void *param, const char *name,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool GetMonitorTarget(const MONITORINFOEX &info,
|
||||||
|
DISPLAYCONFIG_TARGET_DEVICE_NAME &target)
|
||||||
|
{
|
||||||
|
bool found = false;
|
||||||
|
|
||||||
|
UINT32 numPath, numMode;
|
||||||
|
if (GetDisplayConfigBufferSizes(QDC_ONLY_ACTIVE_PATHS, &numPath,
|
||||||
|
&numMode) == ERROR_SUCCESS) {
|
||||||
|
std::vector<DISPLAYCONFIG_PATH_INFO> paths(numPath);
|
||||||
|
std::vector<DISPLAYCONFIG_MODE_INFO> modes(numMode);
|
||||||
|
if (QueryDisplayConfig(QDC_ONLY_ACTIVE_PATHS, &numPath,
|
||||||
|
paths.data(), &numMode, modes.data(),
|
||||||
|
nullptr) == ERROR_SUCCESS) {
|
||||||
|
paths.resize(numPath);
|
||||||
|
for (size_t i = 0; i < numPath; ++i) {
|
||||||
|
const DISPLAYCONFIG_PATH_INFO &path = paths[i];
|
||||||
|
|
||||||
|
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(info.szDevice,
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
|
||||||
static inline void LogAdapterMonitors(IDXGIAdapter1 *adapter)
|
static inline void LogAdapterMonitors(IDXGIAdapter1 *adapter)
|
||||||
{
|
{
|
||||||
UINT i;
|
UINT i;
|
||||||
|
@ -806,15 +853,41 @@ static inline void LogAdapterMonitors(IDXGIAdapter1 *adapter)
|
||||||
if (FAILED(output->GetDesc(&desc)))
|
if (FAILED(output->GetDesc(&desc)))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
RECT rect = desc.DesktopCoordinates;
|
unsigned refresh = 0;
|
||||||
|
|
||||||
|
bool target_found = false;
|
||||||
|
DISPLAYCONFIG_TARGET_DEVICE_NAME target;
|
||||||
|
|
||||||
|
MONITORINFOEX info;
|
||||||
|
info.cbSize = sizeof(info);
|
||||||
|
if (GetMonitorInfo(desc.Monitor, &info)) {
|
||||||
|
target_found = GetMonitorTarget(info, target);
|
||||||
|
|
||||||
|
DEVMODE mode;
|
||||||
|
mode.dmSize = sizeof(mode);
|
||||||
|
mode.dmDriverExtra = 0;
|
||||||
|
if (EnumDisplaySettings(info.szDevice,
|
||||||
|
ENUM_CURRENT_SETTINGS, &mode)) {
|
||||||
|
refresh = mode.dmDisplayFrequency;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!target_found) {
|
||||||
|
target.monitorFriendlyDeviceName[0] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const RECT &rect = desc.DesktopCoordinates;
|
||||||
blog(LOG_INFO,
|
blog(LOG_INFO,
|
||||||
"\t output %u: "
|
"\t output %u: "
|
||||||
"pos={%d, %d}, "
|
"pos={%d, %d}, "
|
||||||
"size={%d, %d}, "
|
"size={%d, %d}, "
|
||||||
"attached=%s",
|
"attached=%s, "
|
||||||
|
"refresh=%u, "
|
||||||
|
"name=%ls",
|
||||||
i, rect.left, rect.top, rect.right - rect.left,
|
i, rect.left, rect.top, rect.right - rect.left,
|
||||||
rect.bottom - rect.top,
|
rect.bottom - rect.top,
|
||||||
desc.AttachedToDesktop ? "true" : "false");
|
desc.AttachedToDesktop ? "true" : "false", refresh,
|
||||||
|
target.monitorFriendlyDeviceName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -853,6 +926,25 @@ static inline void LogD3DAdapters()
|
||||||
blog(LOG_INFO, "\t Shared VRAM: %u",
|
blog(LOG_INFO, "\t Shared VRAM: %u",
|
||||||
desc.SharedSystemMemory);
|
desc.SharedSystemMemory);
|
||||||
|
|
||||||
|
/* driver version */
|
||||||
|
LARGE_INTEGER umd;
|
||||||
|
hr = adapter->CheckInterfaceSupport(__uuidof(IDXGIDevice),
|
||||||
|
&umd);
|
||||||
|
if (SUCCEEDED(hr)) {
|
||||||
|
const uint64_t version = umd.QuadPart;
|
||||||
|
const uint16_t aa = (version >> 48) & 0xffff;
|
||||||
|
const uint16_t bb = (version >> 32) & 0xffff;
|
||||||
|
const uint16_t ccccc = (version >> 16) & 0xffff;
|
||||||
|
const uint16_t ddddd = version & 0xffff;
|
||||||
|
blog(LOG_INFO,
|
||||||
|
"\t Driver Version: %" PRIu16 ".%" PRIu16
|
||||||
|
".%" PRIu16 ".%" PRIu16,
|
||||||
|
aa, bb, ccccc, ddddd);
|
||||||
|
} else {
|
||||||
|
blog(LOG_INFO, "\t Driver Version: Unknown (0x%X)",
|
||||||
|
(unsigned)hr);
|
||||||
|
}
|
||||||
|
|
||||||
LogAdapterMonitors(adapter);
|
LogAdapterMonitors(adapter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -110,7 +110,7 @@ if(WIN32)
|
||||||
endif()
|
endif()
|
||||||
elseif(APPLE)
|
elseif(APPLE)
|
||||||
set(libobs_PLATFORM_SOURCES
|
set(libobs_PLATFORM_SOURCES
|
||||||
obs-cocoa.c
|
obs-cocoa.m
|
||||||
util/threading-posix.c
|
util/threading-posix.c
|
||||||
util/pipe-posix.c
|
util/pipe-posix.c
|
||||||
util/platform-nix.c
|
util/platform-nix.c
|
||||||
|
|
|
@ -29,6 +29,14 @@
|
||||||
#include <IOKit/hid/IOHIDDevice.h>
|
#include <IOKit/hid/IOHIDDevice.h>
|
||||||
#include <IOKit/hid/IOHIDManager.h>
|
#include <IOKit/hid/IOHIDManager.h>
|
||||||
|
|
||||||
|
#import <AppKit/AppKit.h>
|
||||||
|
|
||||||
|
bool is_in_bundle()
|
||||||
|
{
|
||||||
|
NSRunningApplication *app = [NSRunningApplication currentApplication];
|
||||||
|
return [app bundleIdentifier] != nil;
|
||||||
|
}
|
||||||
|
|
||||||
const char *get_module_extension(void)
|
const char *get_module_extension(void)
|
||||||
{
|
{
|
||||||
return ".so";
|
return ".so";
|
||||||
|
@ -51,12 +59,45 @@ void add_default_module_paths(void)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < module_patterns_size; i++)
|
for (int i = 0; i < module_patterns_size; i++)
|
||||||
obs_add_module_path(module_bin[i], module_data[i]);
|
obs_add_module_path(module_bin[i], module_data[i]);
|
||||||
|
|
||||||
|
if (is_in_bundle()) {
|
||||||
|
NSRunningApplication *app =
|
||||||
|
[NSRunningApplication currentApplication];
|
||||||
|
NSURL *bundleURL = [app bundleURL];
|
||||||
|
NSURL *pluginsURL = [bundleURL
|
||||||
|
URLByAppendingPathComponent:@"Contents/Plugins"];
|
||||||
|
NSURL *dataURL = [bundleURL
|
||||||
|
URLByAppendingPathComponent:
|
||||||
|
@"Contents/Resources/data/obs-plugins/%module%"];
|
||||||
|
|
||||||
|
const char *binPath = [[pluginsURL path]
|
||||||
|
cStringUsingEncoding:NSUTF8StringEncoding];
|
||||||
|
const char *dataPath = [[dataURL path]
|
||||||
|
cStringUsingEncoding:NSUTF8StringEncoding];
|
||||||
|
|
||||||
|
obs_add_module_path(binPath, dataPath);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
char *find_libobs_data_file(const char *file)
|
char *find_libobs_data_file(const char *file)
|
||||||
{
|
{
|
||||||
struct dstr path;
|
struct dstr path;
|
||||||
|
|
||||||
|
if (is_in_bundle()) {
|
||||||
|
NSRunningApplication *app =
|
||||||
|
[NSRunningApplication currentApplication];
|
||||||
|
NSURL *bundleURL = [app bundleURL];
|
||||||
|
NSURL *libobsDataURL =
|
||||||
|
[bundleURL URLByAppendingPathComponent:
|
||||||
|
@"Contents/Resources/data/libobs/"];
|
||||||
|
const char *libobsDataPath = [[libobsDataURL path]
|
||||||
|
cStringUsingEncoding:NSUTF8StringEncoding];
|
||||||
|
dstr_init_copy(&path, libobsDataPath);
|
||||||
|
dstr_cat(&path, "/");
|
||||||
|
} else {
|
||||||
dstr_init_copy(&path, OBS_INSTALL_DATA_PATH "/libobs/");
|
dstr_init_copy(&path, OBS_INSTALL_DATA_PATH "/libobs/");
|
||||||
|
}
|
||||||
|
|
||||||
dstr_cat(&path, file);
|
dstr_cat(&path, file);
|
||||||
return path.array;
|
return path.array;
|
||||||
}
|
}
|
||||||
|
@ -111,13 +152,20 @@ static void log_available_memory(void)
|
||||||
memory_available / 1024 / 1024);
|
memory_available / 1024 / 1024);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void log_os_name(id pi, SEL UTF8String)
|
static void log_os_name(id pi, SEL UTF8StringSel)
|
||||||
{
|
{
|
||||||
unsigned long os_id = (unsigned long)objc_msgSend(
|
typedef int (*os_func)(id, SEL);
|
||||||
|
os_func operatingSystem = (os_func)objc_msgSend;
|
||||||
|
unsigned long os_id = (unsigned long)operatingSystem(
|
||||||
pi, sel_registerName("operatingSystem"));
|
pi, sel_registerName("operatingSystem"));
|
||||||
|
|
||||||
id os = objc_msgSend(pi, sel_registerName("operatingSystemName"));
|
typedef id (*os_name_func)(id, SEL);
|
||||||
const char *name = (const char *)objc_msgSend(os, UTF8String);
|
os_name_func operatingSystemName = (os_name_func)objc_msgSend;
|
||||||
|
id os = operatingSystemName(pi,
|
||||||
|
sel_registerName("operatingSystemName"));
|
||||||
|
typedef const char *(*utf8_func)(id, SEL);
|
||||||
|
utf8_func UTF8String = (utf8_func)objc_msgSend;
|
||||||
|
const char *name = UTF8String(os, UTF8StringSel);
|
||||||
|
|
||||||
if (os_id == 5 /*NSMACHOperatingSystem*/) {
|
if (os_id == 5 /*NSMACHOperatingSystem*/) {
|
||||||
blog(LOG_INFO, "OS Name: Mac OS X (%s)", name);
|
blog(LOG_INFO, "OS Name: Mac OS X (%s)", name);
|
||||||
|
@ -127,11 +175,15 @@ static void log_os_name(id pi, SEL UTF8String)
|
||||||
blog(LOG_INFO, "OS Name: %s", name ? name : "Unknown");
|
blog(LOG_INFO, "OS Name: %s", name ? name : "Unknown");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void log_os_version(id pi, SEL UTF8String)
|
static void log_os_version(id pi, SEL UTF8StringSel)
|
||||||
{
|
{
|
||||||
id vs = objc_msgSend(pi,
|
typedef id (*version_func)(id, SEL);
|
||||||
sel_registerName("operatingSystemVersionString"));
|
version_func operatingSystemVersionString = (version_func)objc_msgSend;
|
||||||
const char *version = (const char *)objc_msgSend(vs, UTF8String);
|
id vs = operatingSystemVersionString(
|
||||||
|
pi, sel_registerName("operatingSystemVersionString"));
|
||||||
|
typedef const char *(*utf8_func)(id, SEL);
|
||||||
|
utf8_func UTF8String = (utf8_func)objc_msgSend;
|
||||||
|
const char *version = UTF8String(vs, UTF8StringSel);
|
||||||
|
|
||||||
blog(LOG_INFO, "OS Version: %s", version ? version : "Unknown");
|
blog(LOG_INFO, "OS Version: %s", version ? version : "Unknown");
|
||||||
}
|
}
|
||||||
|
@ -139,8 +191,9 @@ static void log_os_version(id pi, SEL UTF8String)
|
||||||
static void log_os(void)
|
static void log_os(void)
|
||||||
{
|
{
|
||||||
Class NSProcessInfo = objc_getClass("NSProcessInfo");
|
Class NSProcessInfo = objc_getClass("NSProcessInfo");
|
||||||
id pi = objc_msgSend((id)NSProcessInfo,
|
typedef id (*func)(id, SEL);
|
||||||
sel_registerName("processInfo"));
|
func processInfo = (func)objc_msgSend;
|
||||||
|
id pi = processInfo((id)NSProcessInfo, sel_registerName("processInfo"));
|
||||||
|
|
||||||
SEL UTF8String = sel_registerName("UTF8String");
|
SEL UTF8String = sel_registerName("UTF8String");
|
||||||
|
|
||||||
|
@ -1673,9 +1726,11 @@ static bool mouse_button_pressed(obs_key_t key, bool *pressed)
|
||||||
}
|
}
|
||||||
|
|
||||||
Class NSEvent = objc_getClass("NSEvent");
|
Class NSEvent = objc_getClass("NSEvent");
|
||||||
SEL pressedMouseButtons = sel_registerName("pressedMouseButtons");
|
SEL pressedMouseButtonsSel = sel_registerName("pressedMouseButtons");
|
||||||
NSUInteger buttons =
|
typedef int (*func)(id, SEL);
|
||||||
(NSUInteger)objc_msgSend((id)NSEvent, pressedMouseButtons);
|
func pressedMouseButtons = (func)objc_msgSend;
|
||||||
|
NSUInteger buttons = (NSUInteger)pressedMouseButtons(
|
||||||
|
(id)NSEvent, pressedMouseButtonsSel);
|
||||||
|
|
||||||
*pressed = (buttons & (1 << button)) != 0;
|
*pressed = (buttons & (1 << button)) != 0;
|
||||||
return true;
|
return true;
|
|
@ -41,7 +41,7 @@
|
||||||
*
|
*
|
||||||
* Reset to zero each major or minor version
|
* Reset to zero each major or minor version
|
||||||
*/
|
*/
|
||||||
#define LIBOBS_API_PATCH_VER 3
|
#define LIBOBS_API_PATCH_VER 5
|
||||||
|
|
||||||
#define MAKE_SEMANTIC_VERSION(major, minor, patch) \
|
#define MAKE_SEMANTIC_VERSION(major, minor, patch) \
|
||||||
((major << 24) | (minor << 16) | patch)
|
((major << 24) | (minor << 16) | patch)
|
||||||
|
|
|
@ -58,9 +58,10 @@ static void *gpu_encode_thread(void *unused)
|
||||||
video_output_inc_texture_frames(video->video);
|
video_output_inc_texture_frames(video->video);
|
||||||
|
|
||||||
for (size_t i = 0; i < video->gpu_encoders.num; i++) {
|
for (size_t i = 0; i < video->gpu_encoders.num; i++) {
|
||||||
obs_encoder_t *encoder = video->gpu_encoders.array[i];
|
obs_encoder_t *encoder = obs_encoder_get_ref(
|
||||||
|
video->gpu_encoders.array[i]);
|
||||||
|
if (encoder)
|
||||||
da_push_back(encoders, &encoder);
|
da_push_back(encoders, &encoder);
|
||||||
obs_encoder_addref(encoder);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pthread_mutex_unlock(&video->gpu_encoder_mutex);
|
pthread_mutex_unlock(&video->gpu_encoder_mutex);
|
||||||
|
|
|
@ -664,7 +664,8 @@ void XCompcapMain::render(gs_effect_t *effect)
|
||||||
effect = obs_get_base_effect(OBS_EFFECT_DEFAULT);
|
effect = obs_get_base_effect(OBS_EFFECT_DEFAULT);
|
||||||
|
|
||||||
while (gs_effect_loop(effect, "Draw")) {
|
while (gs_effect_loop(effect, "Draw")) {
|
||||||
xcursor_render(p->cursor);
|
xcursor_render(p->cursor, -p->cur_cut_left,
|
||||||
|
-p->cur_cut_top);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -103,7 +103,7 @@ void xcursor_tick(xcursor_t *data)
|
||||||
XFree(xc);
|
XFree(xc);
|
||||||
}
|
}
|
||||||
|
|
||||||
void xcursor_render(xcursor_t *data)
|
void xcursor_render(xcursor_t *data, int x_offset, int y_offset)
|
||||||
{
|
{
|
||||||
if (!data->tex)
|
if (!data->tex)
|
||||||
return;
|
return;
|
||||||
|
@ -117,7 +117,8 @@ void xcursor_render(xcursor_t *data)
|
||||||
gs_enable_color(true, true, true, false);
|
gs_enable_color(true, true, true, false);
|
||||||
|
|
||||||
gs_matrix_push();
|
gs_matrix_push();
|
||||||
gs_matrix_translate3f(data->render_x, data->render_y, 0.0f);
|
gs_matrix_translate3f(data->render_x + x_offset,
|
||||||
|
data->render_y + y_offset, 0.0f);
|
||||||
gs_draw_sprite(data->tex, 0, 0, 0);
|
gs_draw_sprite(data->tex, 0, 0, 0);
|
||||||
gs_matrix_pop();
|
gs_matrix_pop();
|
||||||
|
|
||||||
|
|
|
@ -61,7 +61,7 @@ void xcursor_tick(xcursor_t *data);
|
||||||
*
|
*
|
||||||
* This needs to be executed within a valid render context
|
* This needs to be executed within a valid render context
|
||||||
*/
|
*/
|
||||||
void xcursor_render(xcursor_t *data);
|
void xcursor_render(xcursor_t *data, int x_offset, int y_offset);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Specify offset for the cursor
|
* Specify offset for the cursor
|
||||||
|
|
|
@ -108,7 +108,6 @@ int randr_screen_count(xcb_connection_t *xcb)
|
||||||
{
|
{
|
||||||
if (!xcb)
|
if (!xcb)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
xcb_screen_t *screen;
|
xcb_screen_t *screen;
|
||||||
screen = xcb_setup_roots_iterator(xcb_get_setup(xcb)).data;
|
screen = xcb_setup_roots_iterator(xcb_get_setup(xcb)).data;
|
||||||
|
|
||||||
|
|
|
@ -324,7 +324,9 @@ static bool xshm_server_changed(obs_properties_t *props, obs_property_t *p,
|
||||||
")",
|
")",
|
||||||
i, w, h, x, y);
|
i, w, h, x, y);
|
||||||
|
|
||||||
obs_property_list_add_int(screens, screen_info.array, i);
|
if (h > 0 && w > 0)
|
||||||
|
obs_property_list_add_int(screens, screen_info.array,
|
||||||
|
i);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* handle missing screen */
|
/* handle missing screen */
|
||||||
|
|
|
@ -183,7 +183,8 @@ static bool parse_params(AVCodecContext *context, char **opts)
|
||||||
*assign = 0;
|
*assign = 0;
|
||||||
value = assign + 1;
|
value = assign + 1;
|
||||||
|
|
||||||
if (av_opt_set(context->priv_data, name, value, 0)) {
|
if (av_opt_set(context, name, value,
|
||||||
|
AV_OPT_SEARCH_CHILDREN)) {
|
||||||
blog(LOG_WARNING, "Failed to set %s=%s", name,
|
blog(LOG_WARNING, "Failed to set %s=%s", name,
|
||||||
value);
|
value);
|
||||||
ret = false;
|
ret = false;
|
||||||
|
|
|
@ -1342,7 +1342,7 @@ static void check_to_drop_frames(struct rtmp_stream *stream, bool pframes)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (buffer_duration_usec >= DBR_TRIGGER_USEC) {
|
if ((uint64_t)buffer_duration_usec >= DBR_TRIGGER_USEC) {
|
||||||
pthread_mutex_lock(&stream->dbr_mutex);
|
pthread_mutex_lock(&stream->dbr_mutex);
|
||||||
bitrate_changed = dbr_bitrate_lowered(stream);
|
bitrate_changed = dbr_bitrate_lowered(stream);
|
||||||
pthread_mutex_unlock(&stream->dbr_mutex);
|
pthread_mutex_unlock(&stream->dbr_mutex);
|
||||||
|
|
|
@ -1,15 +1,21 @@
|
||||||
project(rtmp-services)
|
project(rtmp-services)
|
||||||
|
|
||||||
|
find_package(Libcurl REQUIRED)
|
||||||
|
|
||||||
|
include_directories(${LIBCURL_INCLUDE_DIRS})
|
||||||
|
|
||||||
include_directories(${OBS_JANSSON_INCLUDE_DIRS})
|
include_directories(${OBS_JANSSON_INCLUDE_DIRS})
|
||||||
|
|
||||||
set(rtmp-services_SOURCES
|
set(rtmp-services_SOURCES
|
||||||
twitch.c
|
twitch.c
|
||||||
|
younow.c
|
||||||
rtmp-common.c
|
rtmp-common.c
|
||||||
rtmp-custom.c
|
rtmp-custom.c
|
||||||
rtmp-services-main.c)
|
rtmp-services-main.c)
|
||||||
|
|
||||||
set(rtmp-services_HEADERS
|
set(rtmp-services_HEADERS
|
||||||
twitch.h
|
twitch.h
|
||||||
|
younow.h
|
||||||
rtmp-format-ver.h)
|
rtmp-format-ver.h)
|
||||||
|
|
||||||
set(RTMP_SERVICES_URL
|
set(RTMP_SERVICES_URL
|
||||||
|
@ -28,10 +34,12 @@ add_library(rtmp-services MODULE
|
||||||
${rtmp-services_SOURCES}
|
${rtmp-services_SOURCES}
|
||||||
${rtmp-services_HEADERS}
|
${rtmp-services_HEADERS}
|
||||||
${rtmp-services_config_HEADERS})
|
${rtmp-services_config_HEADERS})
|
||||||
|
|
||||||
target_link_libraries(rtmp-services
|
target_link_libraries(rtmp-services
|
||||||
libobs
|
libobs
|
||||||
file-updater
|
file-updater
|
||||||
${OBS_JANSSON_IMPORT})
|
${OBS_JANSSON_IMPORT}
|
||||||
|
${LIBCURL_LIBRARIES})
|
||||||
|
|
||||||
target_include_directories(rtmp-services
|
target_include_directories(rtmp-services
|
||||||
PUBLIC
|
PUBLIC
|
||||||
|
|
4
plugins/rtmp-services/data/package.json
Normal file → Executable file
4
plugins/rtmp-services/data/package.json
Normal file → Executable file
|
@ -1,10 +1,10 @@
|
||||||
{
|
{
|
||||||
"url": "https://obsproject.com/obs2_update/rtmp-services",
|
"url": "https://obsproject.com/obs2_update/rtmp-services",
|
||||||
"version": 112,
|
"version": 114,
|
||||||
"files": [
|
"files": [
|
||||||
{
|
{
|
||||||
"name": "services.json",
|
"name": "services.json",
|
||||||
"version": 112
|
"version": 114
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
49
plugins/rtmp-services/data/services.json
Normal file → Executable file
49
plugins/rtmp-services/data/services.json
Normal file → Executable file
|
@ -1465,6 +1465,20 @@
|
||||||
"max audio bitrate": 192
|
"max audio bitrate": 192
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "ChathostessModels",
|
||||||
|
"servers": [
|
||||||
|
{
|
||||||
|
"name": "ChathostessModels - Default",
|
||||||
|
"url": "rtmp://wowza01.foobarweb.com/cmschatsys_video"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"recommended": {
|
||||||
|
"keyint": 2,
|
||||||
|
"max video bitrate": 3000,
|
||||||
|
"max audio bitrate": 128
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "Camplace",
|
"name": "Camplace",
|
||||||
"servers": [
|
"servers": [
|
||||||
|
@ -1500,6 +1514,24 @@
|
||||||
"x264opts": "tune=zerolatency"
|
"x264opts": "tune=zerolatency"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "YouNow",
|
||||||
|
"common": false,
|
||||||
|
"servers": [
|
||||||
|
{
|
||||||
|
"name": "younow.com",
|
||||||
|
"url": "https://signaling-api.younow-prod.video.propsproject.com/api/v1/ingest/server/"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"recommended": {
|
||||||
|
"keyint": 2,
|
||||||
|
"output": "ftl_output",
|
||||||
|
"max audio bitrate": 160,
|
||||||
|
"max video bitrate": 7000,
|
||||||
|
"profile": "main",
|
||||||
|
"bframes": 0
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "Steam",
|
"name": "Steam",
|
||||||
"common": false,
|
"common": false,
|
||||||
|
@ -1559,6 +1591,23 @@
|
||||||
"max video bitrate": 7000,
|
"max video bitrate": 7000,
|
||||||
"max audio bitrate": 128
|
"max audio bitrate": 128
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Stars.AVN.com",
|
||||||
|
"servers": [
|
||||||
|
{
|
||||||
|
"name": "Default",
|
||||||
|
"url": "rtmp://alpha.gateway.stars.avn.com/live"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"recommended": {
|
||||||
|
"keyint": 2,
|
||||||
|
"profile": "main",
|
||||||
|
"max video bitrate": 2500,
|
||||||
|
"max audio bitrate": 192,
|
||||||
|
"bframes": 0,
|
||||||
|
"x264opts": "tune=zerolatency"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
|
|
||||||
#include "rtmp-format-ver.h"
|
#include "rtmp-format-ver.h"
|
||||||
#include "twitch.h"
|
#include "twitch.h"
|
||||||
|
#include "younow.h"
|
||||||
|
|
||||||
struct rtmp_common {
|
struct rtmp_common {
|
||||||
char *service;
|
char *service;
|
||||||
|
@ -485,7 +486,9 @@ static void apply_video_encoder_settings(obs_data_t *settings,
|
||||||
obs_data_set_string(settings, "rate_control", "CBR");
|
obs_data_set_string(settings, "rate_control", "CBR");
|
||||||
|
|
||||||
item = json_object_get(recommended, "profile");
|
item = json_object_get(recommended, "profile");
|
||||||
if (json_is_string(item)) {
|
obs_data_item_t *enc_item = obs_data_item_byname(settings, "profile");
|
||||||
|
if (json_is_string(item) &&
|
||||||
|
obs_data_item_gettype(enc_item) == OBS_DATA_STRING) {
|
||||||
const char *profile = json_string_value(item);
|
const char *profile = json_string_value(item);
|
||||||
obs_data_set_string(settings, "profile", profile);
|
obs_data_set_string(settings, "profile", profile);
|
||||||
}
|
}
|
||||||
|
@ -594,6 +597,12 @@ static const char *rtmp_common_url(void *data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (service->service && strcmp(service->service, "YouNow") == 0) {
|
||||||
|
if (service->server && service->key) {
|
||||||
|
return younow_get_ingest(service->server, service->key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return service->server;
|
return service->server;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
113
plugins/rtmp-services/younow.c
Normal file
113
plugins/rtmp-services/younow.c
Normal file
|
@ -0,0 +1,113 @@
|
||||||
|
#include <curl/curl.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <util/dstr.h>
|
||||||
|
#include "util/base.h"
|
||||||
|
#include "younow.h"
|
||||||
|
|
||||||
|
struct younow_mem_struct {
|
||||||
|
char *memory;
|
||||||
|
size_t size;
|
||||||
|
};
|
||||||
|
|
||||||
|
static char *current_ingest = NULL;
|
||||||
|
|
||||||
|
static size_t younow_write_cb(void *contents, size_t size, size_t nmemb,
|
||||||
|
void *userp)
|
||||||
|
{
|
||||||
|
size_t realsize = size * nmemb;
|
||||||
|
struct younow_mem_struct *mem = (struct younow_mem_struct *)userp;
|
||||||
|
|
||||||
|
mem->memory = realloc(mem->memory, mem->size + realsize + 1);
|
||||||
|
if (mem->memory == NULL) {
|
||||||
|
blog(LOG_WARNING, "yyounow_write_cb: realloc returned NULL");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(&(mem->memory[mem->size]), contents, realsize);
|
||||||
|
mem->size += realsize;
|
||||||
|
mem->memory[mem->size] = 0;
|
||||||
|
|
||||||
|
return realsize;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *younow_get_ingest(const char *server, const char *key)
|
||||||
|
{
|
||||||
|
CURL *curl_handle;
|
||||||
|
CURLcode res;
|
||||||
|
struct younow_mem_struct chunk;
|
||||||
|
struct dstr uri;
|
||||||
|
long response_code;
|
||||||
|
|
||||||
|
// find the delimiter in stream key
|
||||||
|
const char *delim = strchr(key, '_');
|
||||||
|
if (delim == NULL) {
|
||||||
|
blog(LOG_WARNING,
|
||||||
|
"younow_get_ingest: delimiter not found in stream key");
|
||||||
|
return server;
|
||||||
|
}
|
||||||
|
|
||||||
|
curl_handle = curl_easy_init();
|
||||||
|
|
||||||
|
chunk.memory = malloc(1); /* will be grown as needed by realloc */
|
||||||
|
chunk.size = 0; /* no data at this point */
|
||||||
|
|
||||||
|
dstr_init(&uri);
|
||||||
|
dstr_copy(&uri, server);
|
||||||
|
dstr_ncat(&uri, key, delim - key);
|
||||||
|
|
||||||
|
curl_easy_setopt(curl_handle, CURLOPT_URL, uri.array);
|
||||||
|
curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYPEER, true);
|
||||||
|
curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYHOST, 2L);
|
||||||
|
curl_easy_setopt(curl_handle, CURLOPT_TIMEOUT, 3L);
|
||||||
|
curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, younow_write_cb);
|
||||||
|
curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *)&chunk);
|
||||||
|
|
||||||
|
#if LIBCURL_VERSION_NUM >= 0x072400
|
||||||
|
// A lot of servers don't yet support ALPN
|
||||||
|
curl_easy_setopt(curl_handle, CURLOPT_SSL_ENABLE_ALPN, 0);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
res = curl_easy_perform(curl_handle);
|
||||||
|
dstr_free(&uri);
|
||||||
|
|
||||||
|
if (res != CURLE_OK) {
|
||||||
|
blog(LOG_WARNING,
|
||||||
|
"younow_get_ingest: curl_easy_perform() failed: %s",
|
||||||
|
curl_easy_strerror(res));
|
||||||
|
curl_easy_cleanup(curl_handle);
|
||||||
|
free(chunk.memory);
|
||||||
|
return server;
|
||||||
|
}
|
||||||
|
|
||||||
|
curl_easy_getinfo(curl_handle, CURLINFO_RESPONSE_CODE, &response_code);
|
||||||
|
if (response_code != 200) {
|
||||||
|
blog(LOG_WARNING,
|
||||||
|
"younow_get_ingest: curl_easy_perform() returned code: %ld",
|
||||||
|
response_code);
|
||||||
|
curl_easy_cleanup(curl_handle);
|
||||||
|
free(chunk.memory);
|
||||||
|
return server;
|
||||||
|
}
|
||||||
|
|
||||||
|
curl_easy_cleanup(curl_handle);
|
||||||
|
|
||||||
|
if (chunk.size == 0) {
|
||||||
|
blog(LOG_WARNING,
|
||||||
|
"younow_get_ingest: curl_easy_perform() returned empty response");
|
||||||
|
free(chunk.memory);
|
||||||
|
return server;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (current_ingest) {
|
||||||
|
free(current_ingest);
|
||||||
|
current_ingest = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
current_ingest = strdup(chunk.memory);
|
||||||
|
free(chunk.memory);
|
||||||
|
blog(LOG_INFO, "younow_get_ingest: returning ingest: %s",
|
||||||
|
current_ingest);
|
||||||
|
return current_ingest;
|
||||||
|
}
|
3
plugins/rtmp-services/younow.h
Normal file
3
plugins/rtmp-services/younow.h
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
extern const char *younow_get_ingest(const char *server, const char *key);
|
Loading…
Reference in a new issue