New upstream version 26.0.2+dfsg1
This commit is contained in:
parent
bc27b6c1ca
commit
040dcc3fc2
23 changed files with 226 additions and 184 deletions
|
@ -9,7 +9,7 @@ env:
|
||||||
task:
|
task:
|
||||||
install_script:
|
install_script:
|
||||||
- pkg install -y
|
- pkg install -y
|
||||||
v4l_compat swig30 ffmpeg curl dbus fdk-aac fontconfig
|
v4l_compat swig ffmpeg curl dbus fdk-aac fontconfig
|
||||||
freetype2 jackit jansson luajit mbedtls pulseaudio speexdsp
|
freetype2 jackit jansson luajit mbedtls pulseaudio speexdsp
|
||||||
libsysinfo libudev-devd libv4l libx264 cmake ninja
|
libsysinfo libudev-devd libv4l libx264 cmake ninja
|
||||||
mesa-libs lua52 pkgconf
|
mesa-libs lua52 pkgconf
|
||||||
|
|
6
.github/workflows/main.yml
vendored
6
.github/workflows/main.yml
vendored
|
@ -236,8 +236,14 @@ jobs:
|
||||||
|
|
||||||
cp ../CI/scripts/macos/app/OBSPublicDSAKey.pem ./OBS.app/Contents/Resources
|
cp ../CI/scripts/macos/app/OBSPublicDSAKey.pem ./OBS.app/Contents/Resources
|
||||||
|
|
||||||
|
if [ "${GITHUB_REF:0:10}" = "refs/tags/" ]; then
|
||||||
|
plutil -insert CFBundleVersion -string ${{ env.OBS_GIT_TAG }} ./OBS.app/Contents/Info.plist
|
||||||
|
plutil -insert CFBundleShortVersionString -string ${{ env.OBS_GIT_TAG }} ./OBS.app/Contents/Info.plist
|
||||||
|
else
|
||||||
plutil -insert CFBundleVersion -string ${{ env.OBS_GIT_TAG }}-${{ env.OBS_GIT_HASH }} ./OBS.app/Contents/Info.plist
|
plutil -insert CFBundleVersion -string ${{ env.OBS_GIT_TAG }}-${{ env.OBS_GIT_HASH }} ./OBS.app/Contents/Info.plist
|
||||||
plutil -insert CFBundleShortVersionString -string ${{ env.OBS_GIT_TAG }}-${{ env.OBS_GIT_HASH }} ./OBS.app/Contents/Info.plist
|
plutil -insert CFBundleShortVersionString -string ${{ env.OBS_GIT_TAG }}-${{ env.OBS_GIT_HASH }} ./OBS.app/Contents/Info.plist
|
||||||
|
fi
|
||||||
|
|
||||||
plutil -insert OBSFeedsURL -string https://obsproject.com/osx_update/feeds.xml ./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 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
|
plutil -insert SUPublicDSAKeyFile -string OBSPublicDSAKey.pem ./OBS.app/Contents/Info.plist
|
||||||
|
|
|
@ -219,6 +219,13 @@ Var dllFilesInUse
|
||||||
|
|
||||||
Function checkDLLs
|
Function checkDLLs
|
||||||
OBSInstallerUtils::ResetInUseFileChecks
|
OBSInstallerUtils::ResetInUseFileChecks
|
||||||
|
!ifdef INSTALL64
|
||||||
|
OBSInstallerUtils::AddInUseFileCheck "$INSTDIR\bin\64bit\avutil-56.dll"
|
||||||
|
OBSInstallerUtils::AddInUseFileCheck "$INSTDIR\bin\64bit\swscale-5.dll"
|
||||||
|
!else
|
||||||
|
OBSInstallerUtils::AddInUseFileCheck "$INSTDIR\bin\32bit\avutil-56.dll"
|
||||||
|
OBSInstallerUtils::AddInUseFileCheck "$INSTDIR\bin\32bit\swscale-5.dll"
|
||||||
|
!endif
|
||||||
OBSInstallerUtils::AddInUseFileCheck "$INSTDIR\data\obs-plugins\win-capture\graphics-hook32.dll"
|
OBSInstallerUtils::AddInUseFileCheck "$INSTDIR\data\obs-plugins\win-capture\graphics-hook32.dll"
|
||||||
OBSInstallerUtils::AddInUseFileCheck "$INSTDIR\data\obs-plugins\win-capture\graphics-hook64.dll"
|
OBSInstallerUtils::AddInUseFileCheck "$INSTDIR\data\obs-plugins\win-capture\graphics-hook64.dll"
|
||||||
OBSInstallerUtils::AddInUseFileCheck "$INSTDIR\data\obs-plugins\win-dshow\obs-virtualcam-module32.dll"
|
OBSInstallerUtils::AddInUseFileCheck "$INSTDIR\data\obs-plugins\win-dshow\obs-virtualcam-module32.dll"
|
||||||
|
|
|
@ -1981,7 +1981,7 @@ static int run_program(fstream &logFile, int argc, char *argv[])
|
||||||
run:
|
run:
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !defined(_WIN32) && !defined(__APPLE__)
|
#if !defined(_WIN32) && !defined(__APPLE__) && !defined(__FreeBSD__)
|
||||||
// Mounted by termina during chromeOS linux container startup
|
// Mounted by termina during chromeOS linux container startup
|
||||||
// https://chromium.googlesource.com/chromiumos/overlays/board-overlays/+/master/project-termina/chromeos-base/termina-lxd-scripts/files/lxd_setup.sh
|
// https://chromium.googlesource.com/chromiumos/overlays/board-overlays/+/master/project-termina/chromeos-base/termina-lxd-scripts/files/lxd_setup.sh
|
||||||
os_dir_t *crosDir = os_opendir("/opt/google/cros-containers");
|
os_dir_t *crosDir = os_opendir("/opt/google/cros-containers");
|
||||||
|
|
|
@ -144,6 +144,13 @@ bool IsAlwaysOnTop(QWidget *window)
|
||||||
return (window->windowFlags() & Qt::WindowStaysOnTopHint) != 0;
|
return (window->windowFlags() & Qt::WindowStaysOnTopHint) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void disableColorSpaceConversion(QWidget *window)
|
||||||
|
{
|
||||||
|
NSView *view =
|
||||||
|
(__bridge NSView *)reinterpret_cast<void *>(window->winId());
|
||||||
|
view.window.colorSpace = NSColorSpace.sRGBColorSpace;
|
||||||
|
}
|
||||||
|
|
||||||
void SetAlwaysOnTop(QWidget *window, bool enable)
|
void SetAlwaysOnTop(QWidget *window, bool enable)
|
||||||
{
|
{
|
||||||
Qt::WindowFlags flags = window->windowFlags();
|
Qt::WindowFlags flags = window->windowFlags();
|
||||||
|
|
|
@ -67,4 +67,5 @@ QString GetMonitorName(const QString &id);
|
||||||
void EnableOSXVSync(bool enable);
|
void EnableOSXVSync(bool enable);
|
||||||
void EnableOSXDockIcon(bool enable);
|
void EnableOSXDockIcon(bool enable);
|
||||||
void InstallNSApplicationSubclass();
|
void InstallNSApplicationSubclass();
|
||||||
|
void disableColorSpaceConversion(QWidget *window);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -531,6 +531,8 @@ VolumeMeter::VolumeMeter(QWidget *parent, obs_volmeter_t *obs_volmeter,
|
||||||
bool vertical)
|
bool vertical)
|
||||||
: QWidget(parent), obs_volmeter(obs_volmeter), vertical(vertical)
|
: QWidget(parent), obs_volmeter(obs_volmeter), vertical(vertical)
|
||||||
{
|
{
|
||||||
|
setAttribute(Qt::WA_OpaquePaintEvent, true);
|
||||||
|
|
||||||
// Use a font that can be rendered small.
|
// Use a font that can be rendered small.
|
||||||
tickFont = QFont("Arial");
|
tickFont = QFont("Arial");
|
||||||
tickFont.setPixelSize(7);
|
tickFont.setPixelSize(7);
|
||||||
|
@ -1041,6 +1043,11 @@ void VolumeMeter::paintEvent(QPaintEvent *event)
|
||||||
|
|
||||||
// Actual painting of the widget starts here.
|
// Actual painting of the widget starts here.
|
||||||
QPainter painter(this);
|
QPainter painter(this);
|
||||||
|
|
||||||
|
// Paint window background color (as widget is opaque)
|
||||||
|
QColor background = palette().color(QPalette::ColorRole::Window);
|
||||||
|
painter.fillRect(rect, background);
|
||||||
|
|
||||||
if (vertical) {
|
if (vertical) {
|
||||||
// Invert the Y axis to ease the math
|
// Invert the Y axis to ease the math
|
||||||
painter.translate(0, height);
|
painter.translate(0, height);
|
||||||
|
|
|
@ -45,11 +45,13 @@ void StringToHash(const wchar_t *in, BYTE *out)
|
||||||
|
|
||||||
bool CalculateFileHash(const wchar_t *path, BYTE *hash)
|
bool CalculateFileHash(const wchar_t *path, BYTE *hash)
|
||||||
{
|
{
|
||||||
static BYTE hashBuffer[1048576];
|
static __declspec(thread) vector<BYTE> hashBuffer;
|
||||||
blake2b_state blake2;
|
blake2b_state blake2;
|
||||||
if (blake2b_init(&blake2, BLAKE2_HASH_LENGTH) != 0)
|
if (blake2b_init(&blake2, BLAKE2_HASH_LENGTH) != 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
hashBuffer.resize(1048576);
|
||||||
|
|
||||||
WinHandle handle = CreateFileW(path, GENERIC_READ, FILE_SHARE_READ,
|
WinHandle handle = CreateFileW(path, GENERIC_READ, FILE_SHARE_READ,
|
||||||
nullptr, OPEN_EXISTING, 0, nullptr);
|
nullptr, OPEN_EXISTING, 0, nullptr);
|
||||||
if (handle == INVALID_HANDLE_VALUE)
|
if (handle == INVALID_HANDLE_VALUE)
|
||||||
|
@ -57,14 +59,14 @@ bool CalculateFileHash(const wchar_t *path, BYTE *hash)
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
DWORD read = 0;
|
DWORD read = 0;
|
||||||
if (!ReadFile(handle, hashBuffer, sizeof(hashBuffer), &read,
|
if (!ReadFile(handle, &hashBuffer[0], hashBuffer.size(), &read,
|
||||||
nullptr))
|
nullptr))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!read)
|
if (!read)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (blake2b_update(&blake2, hashBuffer, read) != 0)
|
if (blake2b_update(&blake2, &hashBuffer[0], read) != 0)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1427,6 +1427,23 @@ static bool Update(wchar_t *cmdLine)
|
||||||
/* ------------------------------------- *
|
/* ------------------------------------- *
|
||||||
* Install virtual camera */
|
* Install virtual camera */
|
||||||
|
|
||||||
|
auto runcommand = [](wchar_t *cmd) {
|
||||||
|
STARTUPINFO si = {};
|
||||||
|
si.cb = sizeof(si);
|
||||||
|
si.dwFlags = STARTF_USESHOWWINDOW;
|
||||||
|
si.wShowWindow = SW_HIDE;
|
||||||
|
|
||||||
|
PROCESS_INFORMATION pi;
|
||||||
|
bool success = !!CreateProcessW(nullptr, cmd, nullptr, nullptr,
|
||||||
|
false, CREATE_NEW_CONSOLE,
|
||||||
|
nullptr, nullptr, &si, &pi);
|
||||||
|
if (success) {
|
||||||
|
WaitForSingleObject(pi.hProcess, INFINITE);
|
||||||
|
CloseHandle(pi.hThread);
|
||||||
|
CloseHandle(pi.hProcess);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
if (!bIsPortable) {
|
if (!bIsPortable) {
|
||||||
wchar_t regsvr[MAX_PATH];
|
wchar_t regsvr[MAX_PATH];
|
||||||
wchar_t src[MAX_PATH];
|
wchar_t src[MAX_PATH];
|
||||||
|
@ -1441,20 +1458,20 @@ static bool Update(wchar_t *cmdLine)
|
||||||
StringCbCat(src, sizeof(src),
|
StringCbCat(src, sizeof(src),
|
||||||
L"\\data\\obs-plugins\\win-dshow\\");
|
L"\\data\\obs-plugins\\win-dshow\\");
|
||||||
|
|
||||||
StringCbCopy(tmp, sizeof(tmp), L"\"\"");
|
StringCbCopy(tmp, sizeof(tmp), L"\"");
|
||||||
StringCbCat(tmp, sizeof(tmp), regsvr);
|
StringCbCat(tmp, sizeof(tmp), regsvr);
|
||||||
StringCbCat(tmp, sizeof(tmp), L"\" /s \"");
|
StringCbCat(tmp, sizeof(tmp), L"\" /s \"");
|
||||||
StringCbCat(tmp, sizeof(tmp), src);
|
StringCbCat(tmp, sizeof(tmp), src);
|
||||||
StringCbCat(tmp, sizeof(tmp), L"obs-virtualcam-module");
|
StringCbCat(tmp, sizeof(tmp), L"obs-virtualcam-module");
|
||||||
|
|
||||||
StringCbCopy(tmp2, sizeof(tmp2), tmp);
|
StringCbCopy(tmp2, sizeof(tmp2), tmp);
|
||||||
StringCbCat(tmp2, sizeof(tmp2), L"32.dll\"\"");
|
StringCbCat(tmp2, sizeof(tmp2), L"32.dll\"");
|
||||||
_wsystem(tmp2);
|
runcommand(tmp2);
|
||||||
|
|
||||||
if (is_64bit_windows()) {
|
if (is_64bit_windows()) {
|
||||||
StringCbCopy(tmp2, sizeof(tmp2), tmp);
|
StringCbCopy(tmp2, sizeof(tmp2), tmp);
|
||||||
StringCbCat(tmp2, sizeof(tmp2), L"64.dll\"\"");
|
StringCbCat(tmp2, sizeof(tmp2), L"64.dll\"");
|
||||||
_wsystem(tmp2);
|
runcommand(tmp2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -50,8 +50,14 @@ static inline QString MakeQuickTransitionText(QuickTransition *qt)
|
||||||
|
|
||||||
void OBSBasic::InitDefaultTransitions()
|
void OBSBasic::InitDefaultTransitions()
|
||||||
{
|
{
|
||||||
|
struct AddTransitionVal {
|
||||||
|
QString id;
|
||||||
|
QString name;
|
||||||
|
};
|
||||||
|
|
||||||
ui->transitions->blockSignals(true);
|
ui->transitions->blockSignals(true);
|
||||||
std::vector<OBSSource> transitions;
|
std::vector<OBSSource> transitions;
|
||||||
|
std::vector<AddTransitionVal> addables;
|
||||||
size_t idx = 0;
|
size_t idx = 0;
|
||||||
const char *id;
|
const char *id;
|
||||||
|
|
||||||
|
@ -73,25 +79,57 @@ void OBSBasic::InitDefaultTransitions()
|
||||||
|
|
||||||
obs_source_release(tr);
|
obs_source_release(tr);
|
||||||
} else {
|
} else {
|
||||||
QString addString = QTStr("Add") +
|
AddTransitionVal val;
|
||||||
QStringLiteral(": ") +
|
val.name = QTStr("Add") + QStringLiteral(": ") +
|
||||||
QT_UTF8(name);
|
QT_UTF8(name);
|
||||||
ui->transitions->addItem(
|
val.id = QT_UTF8(id);
|
||||||
addString,
|
addables.push_back(val);
|
||||||
QVariant::fromValue(QString(QT_UTF8(id))));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ui->transitions->count())
|
|
||||||
ui->transitions->insertSeparator(ui->transitions->count());
|
|
||||||
|
|
||||||
for (OBSSource &tr : transitions) {
|
for (OBSSource &tr : transitions) {
|
||||||
ui->transitions->addItem(QT_UTF8(obs_source_get_name(tr)),
|
ui->transitions->addItem(QT_UTF8(obs_source_get_name(tr)),
|
||||||
QVariant::fromValue(OBSSource(tr)));
|
QVariant::fromValue(OBSSource(tr)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (addables.size())
|
||||||
|
ui->transitions->insertSeparator(ui->transitions->count());
|
||||||
|
|
||||||
|
for (AddTransitionVal &val : addables) {
|
||||||
|
ui->transitions->addItem(val.name, QVariant::fromValue(val.id));
|
||||||
|
}
|
||||||
|
|
||||||
ui->transitions->blockSignals(false);
|
ui->transitions->blockSignals(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int OBSBasic::TransitionCount()
|
||||||
|
{
|
||||||
|
int idx = 0;
|
||||||
|
for (int i = 0; i < ui->transitions->count(); i++) {
|
||||||
|
QVariant v = ui->transitions->itemData(i);
|
||||||
|
if (!v.toString().isEmpty()) {
|
||||||
|
idx = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* should always have at least fade and cut due to them being
|
||||||
|
* defaults */
|
||||||
|
assert(idx != 0);
|
||||||
|
return idx - 1; /* remove separator from equation */
|
||||||
|
}
|
||||||
|
|
||||||
|
int OBSBasic::AddTransitionBeforeSeparator(const QString &name,
|
||||||
|
obs_source_t *source)
|
||||||
|
{
|
||||||
|
int idx = TransitionCount();
|
||||||
|
ui->transitions->blockSignals(true);
|
||||||
|
ui->transitions->insertItem(idx, name,
|
||||||
|
QVariant::fromValue(OBSSource(source)));
|
||||||
|
ui->transitions->blockSignals(false);
|
||||||
|
return idx;
|
||||||
|
}
|
||||||
|
|
||||||
void OBSBasic::AddQuickTransitionHotkey(QuickTransition *qt)
|
void OBSBasic::AddQuickTransitionHotkey(QuickTransition *qt)
|
||||||
{
|
{
|
||||||
DStr hotkeyId;
|
DStr hotkeyId;
|
||||||
|
@ -506,10 +544,9 @@ void OBSBasic::AddTransition(QString id)
|
||||||
source = obs_source_create_private(QT_TO_UTF8(id), name.c_str(),
|
source = obs_source_create_private(QT_TO_UTF8(id), name.c_str(),
|
||||||
NULL);
|
NULL);
|
||||||
InitTransition(source);
|
InitTransition(source);
|
||||||
ui->transitions->addItem(
|
int idx = AddTransitionBeforeSeparator(QT_UTF8(name.c_str()),
|
||||||
QT_UTF8(name.c_str()),
|
source);
|
||||||
QVariant::fromValue(OBSSource(source)));
|
ui->transitions->setCurrentIndex(idx);
|
||||||
ui->transitions->setCurrentIndex(ui->transitions->count() - 1);
|
|
||||||
CreatePropertiesWindow(source);
|
CreatePropertiesWindow(source);
|
||||||
obs_source_release(source);
|
obs_source_release(source);
|
||||||
|
|
||||||
|
@ -548,7 +585,15 @@ void OBSBasic::on_transitionRemove_clicked()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ui->transitions->blockSignals(true);
|
||||||
ui->transitions->removeItem(idx);
|
ui->transitions->removeItem(idx);
|
||||||
|
ui->transitions->setCurrentIndex(-1);
|
||||||
|
ui->transitions->blockSignals(false);
|
||||||
|
|
||||||
|
int bottomIdx = TransitionCount() - 1;
|
||||||
|
if (idx > bottomIdx)
|
||||||
|
idx = bottomIdx;
|
||||||
|
ui->transitions->setCurrentIndex(idx);
|
||||||
|
|
||||||
if (api)
|
if (api)
|
||||||
api->on_event(OBS_FRONTEND_EVENT_TRANSITION_LIST_CHANGED);
|
api->on_event(OBS_FRONTEND_EVENT_TRANSITION_LIST_CHANGED);
|
||||||
|
@ -1540,9 +1585,7 @@ void OBSBasic::LoadTransitions(obs_data_array_t *transitions)
|
||||||
obs_source_create_private(id, name, settings);
|
obs_source_create_private(id, name, settings);
|
||||||
if (!obs_obj_invalid(source)) {
|
if (!obs_obj_invalid(source)) {
|
||||||
InitTransition(source);
|
InitTransition(source);
|
||||||
ui->transitions->addItem(
|
AddTransitionBeforeSeparator(QT_UTF8(name), source);
|
||||||
QT_UTF8(name),
|
|
||||||
QVariant::fromValue(OBSSource(source)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
obs_data_release(settings);
|
obs_data_release(settings);
|
||||||
|
|
|
@ -326,6 +326,10 @@ OBSBasic::OBSBasic(QWidget *parent)
|
||||||
renameSource->setShortcut({Qt::Key_F2});
|
renameSource->setShortcut({Qt::Key_F2});
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef __linux__
|
||||||
|
ui->actionE_xit->setShortcut(Qt::CTRL + Qt::Key_Q);
|
||||||
|
#endif
|
||||||
|
|
||||||
auto addNudge = [this](const QKeySequence &seq, const char *s) {
|
auto addNudge = [this](const QKeySequence &seq, const char *s) {
|
||||||
QAction *nudge = new QAction(ui->preview);
|
QAction *nudge = new QAction(ui->preview);
|
||||||
nudge->setShortcut(seq);
|
nudge->setShortcut(seq);
|
||||||
|
@ -1554,6 +1558,8 @@ void OBSBasic::AddVCamButton()
|
||||||
|
|
||||||
vcamButton->setProperty("themeID", "vcamButton");
|
vcamButton->setProperty("themeID", "vcamButton");
|
||||||
ui->buttonsVLayout->insertWidget(2, vcamButton);
|
ui->buttonsVLayout->insertWidget(2, vcamButton);
|
||||||
|
setTabOrder(ui->recordButton, vcamButton);
|
||||||
|
setTabOrder(vcamButton, ui->modeSwitch);
|
||||||
}
|
}
|
||||||
|
|
||||||
void OBSBasic::ResetOutputs()
|
void OBSBasic::ResetOutputs()
|
||||||
|
@ -1588,6 +1594,9 @@ void OBSBasic::ResetOutputs()
|
||||||
replayBufferButton->setProperty("themeID",
|
replayBufferButton->setProperty("themeID",
|
||||||
"replayBufferButton");
|
"replayBufferButton");
|
||||||
ui->buttonsVLayout->insertLayout(2, replayLayout);
|
ui->buttonsVLayout->insertLayout(2, replayLayout);
|
||||||
|
setTabOrder(ui->recordButton, replayBufferButton);
|
||||||
|
setTabOrder(replayBufferButton,
|
||||||
|
ui->buttonsVLayout->itemAt(3)->widget());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sysTrayReplayBuffer)
|
if (sysTrayReplayBuffer)
|
||||||
|
@ -1867,6 +1876,10 @@ void OBSBasic::OBSInit()
|
||||||
SystemTray(true);
|
SystemTray(true);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
disableColorSpaceConversion(this);
|
||||||
|
#endif
|
||||||
|
|
||||||
bool has_last_version = config_has_user_value(App()->GlobalConfig(),
|
bool has_last_version = config_has_user_value(App()->GlobalConfig(),
|
||||||
"General", "LastVersion");
|
"General", "LastVersion");
|
||||||
bool first_run =
|
bool first_run =
|
||||||
|
@ -7035,15 +7048,6 @@ OBSProjector *OBSBasic::OpenProjector(obs_source_t *source, int monitor,
|
||||||
if (monitor > 9 || monitor > QGuiApplication::screens().size() - 1)
|
if (monitor > 9 || monitor > QGuiApplication::screens().size() - 1)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
if (monitor > -1) {
|
|
||||||
for (size_t i = 0; i < projectors.size(); i++) {
|
|
||||||
if (projectors[i]->GetMonitor() == monitor) {
|
|
||||||
DeleteProjector(projectors[i]);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
OBSProjector *projector =
|
OBSProjector *projector =
|
||||||
new OBSProjector(nullptr, source, monitor, type);
|
new OBSProjector(nullptr, source, monitor, type);
|
||||||
|
|
||||||
|
@ -8211,6 +8215,10 @@ void OBSBasic::UpdateReplayBuffer(bool activate)
|
||||||
connect(replay.data(), &QAbstractButton::clicked, this,
|
connect(replay.data(), &QAbstractButton::clicked, this,
|
||||||
&OBSBasic::ReplayBufferSave);
|
&OBSBasic::ReplayBufferSave);
|
||||||
replayLayout->addWidget(replay.data());
|
replayLayout->addWidget(replay.data());
|
||||||
|
setTabOrder(replayLayout->itemAt(0)->widget(),
|
||||||
|
replayLayout->itemAt(1)->widget());
|
||||||
|
setTabOrder(replayLayout->itemAt(1)->widget(),
|
||||||
|
ui->buttonsVLayout->itemAt(3)->widget());
|
||||||
}
|
}
|
||||||
|
|
||||||
#define MBYTE (1024ULL * 1024ULL)
|
#define MBYTE (1024ULL * 1024ULL)
|
||||||
|
|
|
@ -401,6 +401,9 @@ private:
|
||||||
|
|
||||||
void CreateProgramDisplay();
|
void CreateProgramDisplay();
|
||||||
void CreateProgramOptions();
|
void CreateProgramOptions();
|
||||||
|
int TransitionCount();
|
||||||
|
int AddTransitionBeforeSeparator(const QString &name,
|
||||||
|
obs_source_t *source);
|
||||||
void AddQuickTransitionId(int id);
|
void AddQuickTransitionId(int id);
|
||||||
void AddQuickTransition();
|
void AddQuickTransition();
|
||||||
void AddQuickTransitionHotkey(QuickTransition *qt);
|
void AddQuickTransitionHotkey(QuickTransition *qt);
|
||||||
|
|
|
@ -32,7 +32,9 @@ find_path(Libfdk_INCLUDE_DIR
|
||||||
${DepsPath}
|
${DepsPath}
|
||||||
${_LIBFDK_INCLUDE_DIRS}
|
${_LIBFDK_INCLUDE_DIRS}
|
||||||
PATHS
|
PATHS
|
||||||
/usr/include /usr/local/include /opt/local/include /sw/include)
|
/usr/include /usr/local/include /opt/local/include /sw/include
|
||||||
|
PATH_SUFFIXES
|
||||||
|
include)
|
||||||
|
|
||||||
find_library(Libfdk_LIB
|
find_library(Libfdk_LIB
|
||||||
NAMES ${_LIBFDK_LIBRARIES} fdk-aac libfdk-aac
|
NAMES ${_LIBFDK_LIBRARIES} fdk-aac libfdk-aac
|
||||||
|
|
|
@ -137,58 +137,6 @@ struct winrt_capture {
|
||||||
BOOL active;
|
BOOL active;
|
||||||
struct winrt_capture *next;
|
struct winrt_capture *next;
|
||||||
|
|
||||||
void draw_cursor()
|
|
||||||
{
|
|
||||||
CURSORINFO ci{};
|
|
||||||
ci.cbSize = sizeof(CURSORINFO);
|
|
||||||
if (!GetCursorInfo(&ci))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!(ci.flags & CURSOR_SHOWING))
|
|
||||||
return;
|
|
||||||
|
|
||||||
HICON icon = CopyIcon(ci.hCursor);
|
|
||||||
if (!icon)
|
|
||||||
return;
|
|
||||||
|
|
||||||
ICONINFO ii;
|
|
||||||
if (GetIconInfo(icon, &ii)) {
|
|
||||||
POINT win_pos{};
|
|
||||||
if (window) {
|
|
||||||
if (client_area) {
|
|
||||||
ClientToScreen(window, &win_pos);
|
|
||||||
} else {
|
|
||||||
RECT window_rect;
|
|
||||||
if (DwmGetWindowAttribute(
|
|
||||||
window,
|
|
||||||
DWMWA_EXTENDED_FRAME_BOUNDS,
|
|
||||||
&window_rect,
|
|
||||||
sizeof(window_rect)) ==
|
|
||||||
S_OK) {
|
|
||||||
win_pos.x = window_rect.left;
|
|
||||||
win_pos.y = window_rect.top;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
POINT pos;
|
|
||||||
pos.x = ci.ptScreenPos.x - (int)ii.xHotspot - win_pos.x;
|
|
||||||
pos.y = ci.ptScreenPos.y - (int)ii.yHotspot - win_pos.y;
|
|
||||||
|
|
||||||
HDC hdc = (HDC)gs_texture_get_dc(texture);
|
|
||||||
|
|
||||||
DrawIconEx(hdc, pos.x, pos.y, icon, 0, 0, 0, NULL,
|
|
||||||
DI_NORMAL);
|
|
||||||
|
|
||||||
gs_texture_release_dc(texture);
|
|
||||||
|
|
||||||
DeleteObject(ii.hbmColor);
|
|
||||||
DeleteObject(ii.hbmMask);
|
|
||||||
}
|
|
||||||
|
|
||||||
DestroyIcon(icon);
|
|
||||||
}
|
|
||||||
|
|
||||||
void on_closed(
|
void on_closed(
|
||||||
winrt::Windows::Graphics::Capture::GraphicsCaptureItem const &,
|
winrt::Windows::Graphics::Capture::GraphicsCaptureItem const &,
|
||||||
winrt::Windows::Foundation::IInspectable const &)
|
winrt::Windows::Foundation::IInspectable const &)
|
||||||
|
@ -256,10 +204,6 @@ struct winrt_capture {
|
||||||
frame_surface.get());
|
frame_surface.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (capture_cursor && cursor_visible) {
|
|
||||||
draw_cursor();
|
|
||||||
}
|
|
||||||
|
|
||||||
texture_written = true;
|
texture_written = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -342,9 +286,9 @@ static void winrt_capture_device_loss_rebuild(void *device_void, void *data)
|
||||||
const winrt::Windows::Graphics::Capture::GraphicsCaptureSession session =
|
const winrt::Windows::Graphics::Capture::GraphicsCaptureSession session =
|
||||||
frame_pool.CreateCaptureSession(item);
|
frame_pool.CreateCaptureSession(item);
|
||||||
|
|
||||||
/* disable cursor capture if possible since ours performs better */
|
|
||||||
if (winrt_capture_cursor_toggle_supported())
|
if (winrt_capture_cursor_toggle_supported())
|
||||||
session.IsCursorCaptureEnabled(false);
|
session.IsCursorCaptureEnabled(capture->capture_cursor &&
|
||||||
|
capture->cursor_visible);
|
||||||
|
|
||||||
capture->item = item;
|
capture->item = item;
|
||||||
capture->device = device;
|
capture->device = device;
|
||||||
|
@ -425,12 +369,13 @@ try {
|
||||||
const BOOL cursor_toggle_supported =
|
const BOOL cursor_toggle_supported =
|
||||||
winrt_capture_cursor_toggle_supported();
|
winrt_capture_cursor_toggle_supported();
|
||||||
if (cursor_toggle_supported)
|
if (cursor_toggle_supported)
|
||||||
session.IsCursorCaptureEnabled(false);
|
session.IsCursorCaptureEnabled(cursor);
|
||||||
|
|
||||||
struct winrt_capture *capture = new winrt_capture{};
|
struct winrt_capture *capture = new winrt_capture{};
|
||||||
capture->window = window;
|
capture->window = window;
|
||||||
capture->client_area = client_area;
|
capture->client_area = client_area;
|
||||||
capture->capture_cursor = cursor && cursor_toggle_supported;
|
capture->capture_cursor = cursor && cursor_toggle_supported;
|
||||||
|
capture->cursor_visible = cursor;
|
||||||
capture->item = item;
|
capture->item = item;
|
||||||
capture->device = device;
|
capture->device = device;
|
||||||
d3d_device->GetImmediateContext(&capture->context);
|
d3d_device->GetImmediateContext(&capture->context);
|
||||||
|
@ -523,8 +468,13 @@ extern "C" EXPORT BOOL winrt_capture_active(const struct winrt_capture *capture)
|
||||||
extern "C" EXPORT void winrt_capture_show_cursor(struct winrt_capture *capture,
|
extern "C" EXPORT void winrt_capture_show_cursor(struct winrt_capture *capture,
|
||||||
BOOL visible)
|
BOOL visible)
|
||||||
{
|
{
|
||||||
|
if (capture->capture_cursor) {
|
||||||
|
if (capture->cursor_visible != visible) {
|
||||||
|
capture->session.IsCursorCaptureEnabled(visible);
|
||||||
capture->cursor_visible = visible;
|
capture->cursor_visible = visible;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
extern "C" EXPORT void winrt_capture_render(struct winrt_capture *capture,
|
extern "C" EXPORT void winrt_capture_render(struct winrt_capture *capture,
|
||||||
gs_effect_t *effect)
|
gs_effect_t *effect)
|
||||||
|
|
|
@ -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 0
|
#define LIBOBS_API_PATCH_VER 2
|
||||||
|
|
||||||
#define MAKE_SEMANTIC_VERSION(major, minor, patch) \
|
#define MAKE_SEMANTIC_VERSION(major, minor, patch) \
|
||||||
((major << 24) | (minor << 16) | patch)
|
((major << 24) | (minor << 16) | patch)
|
||||||
|
|
|
@ -361,49 +361,60 @@ static HMODULE audio_toolbox = NULL;
|
||||||
|
|
||||||
static void release_lib(void)
|
static void release_lib(void)
|
||||||
{
|
{
|
||||||
#define RELEASE_LIB(x) \
|
if (audio_toolbox) {
|
||||||
if (x) { \
|
FreeLibrary(audio_toolbox);
|
||||||
FreeLibrary(x); \
|
audio_toolbox = NULL;
|
||||||
x = NULL; \
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RELEASE_LIB(audio_toolbox);
|
static bool load_from_shell_path(REFKNOWNFOLDERID rfid, const wchar_t *subpath)
|
||||||
#undef RELEASE_LIB
|
{
|
||||||
|
wchar_t *sh_path;
|
||||||
|
if (SHGetKnownFolderPath(rfid, 0, NULL, &sh_path) != S_OK) {
|
||||||
|
CA_LOG(LOG_WARNING, "Could not retrieve shell path");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
wchar_t path[MAX_PATH];
|
||||||
|
_snwprintf(path, MAX_PATH, L"%s\\%s", sh_path, subpath);
|
||||||
|
CoTaskMemFree(sh_path);
|
||||||
|
|
||||||
|
SetDllDirectory(path);
|
||||||
|
audio_toolbox = LoadLibraryW(L"CoreAudioToolbox.dll");
|
||||||
|
SetDllDirectory(nullptr);
|
||||||
|
|
||||||
|
return !!audio_toolbox;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool load_lib(void)
|
static bool load_lib(void)
|
||||||
{
|
{
|
||||||
PWSTR common_path;
|
/* -------------------------------------------- */
|
||||||
if (SHGetKnownFolderPath(FOLDERID_ProgramFilesCommon, 0, NULL,
|
/* attempt to load from path */
|
||||||
&common_path) != S_OK) {
|
|
||||||
CA_LOG(LOG_WARNING, "Could not retrieve common files path");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct dstr path = {0};
|
audio_toolbox = LoadLibraryW(L"CoreAudioToolbox.dll");
|
||||||
dstr_printf(&path, "%S\\Apple\\Apple Application Support", common_path);
|
if (!!audio_toolbox)
|
||||||
CoTaskMemFree(common_path);
|
|
||||||
|
|
||||||
wchar_t *w_path = dstr_to_wcs(&path);
|
|
||||||
dstr_free(&path);
|
|
||||||
|
|
||||||
SetDllDirectory(w_path);
|
|
||||||
bfree(w_path);
|
|
||||||
|
|
||||||
#define LOAD_LIB(x, n) \
|
|
||||||
x = LoadLibrary(TEXT(n)); \
|
|
||||||
if (!x) \
|
|
||||||
CA_LOG(LOG_DEBUG, "Failed loading library '" n "'");
|
|
||||||
|
|
||||||
LOAD_LIB(audio_toolbox, "CoreAudioToolbox.dll");
|
|
||||||
#undef LOAD_LIB
|
|
||||||
|
|
||||||
SetDllDirectory(NULL);
|
|
||||||
|
|
||||||
if (audio_toolbox)
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
release_lib();
|
/* -------------------------------------------- */
|
||||||
|
/* attempt to load from known install locations */
|
||||||
|
|
||||||
|
struct path_list_t {
|
||||||
|
REFKNOWNFOLDERID rfid;
|
||||||
|
const wchar_t *subpath;
|
||||||
|
};
|
||||||
|
|
||||||
|
path_list_t path_list[] = {
|
||||||
|
{FOLDERID_ProgramFilesCommon,
|
||||||
|
L"Apple\\Apple Application Support"},
|
||||||
|
{FOLDERID_ProgramFiles, L"iTunes"},
|
||||||
|
};
|
||||||
|
|
||||||
|
for (auto &val : path_list) {
|
||||||
|
if (load_from_shell_path(val.rfid, val.subpath)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,8 +18,6 @@ typedef struct cocoa_window *cocoa_window_t;
|
||||||
|
|
||||||
NSArray *enumerate_cocoa_windows(void);
|
NSArray *enumerate_cocoa_windows(void);
|
||||||
|
|
||||||
NSArray *filter_nonzero_kcgwindowlayer_sources(NSArray *windows_arr);
|
|
||||||
|
|
||||||
bool find_window(cocoa_window_t cw, obs_data_t *settings, bool force);
|
bool find_window(cocoa_window_t cw, obs_data_t *settings, bool force);
|
||||||
|
|
||||||
void init_window(cocoa_window_t cw, obs_data_t *settings);
|
void init_window(cocoa_window_t cw, obs_data_t *settings);
|
||||||
|
|
|
@ -23,25 +23,14 @@ static NSComparator win_info_cmp = ^(NSDictionary *o1, NSDictionary *o2) {
|
||||||
return [o1[WINDOW_NUMBER] compare:o2[WINDOW_NUMBER]];
|
return [o1[WINDOW_NUMBER] compare:o2[WINDOW_NUMBER]];
|
||||||
};
|
};
|
||||||
|
|
||||||
NSArray *filter_nonzero_kcgwindowlayer_sources(NSArray *windows_arr)
|
|
||||||
{
|
|
||||||
NSPredicate *pred =
|
|
||||||
[NSPredicate predicateWithFormat:@"(kCGWindowLayer == 0)"];
|
|
||||||
NSArray *new_windows_arr =
|
|
||||||
[windows_arr filteredArrayUsingPredicate:pred];
|
|
||||||
|
|
||||||
return new_windows_arr;
|
|
||||||
}
|
|
||||||
|
|
||||||
NSArray *enumerate_windows(void)
|
NSArray *enumerate_windows(void)
|
||||||
{
|
{
|
||||||
NSArray *arr = (NSArray *)CGWindowListCopyWindowInfo(
|
NSArray *arr = (NSArray *)CGWindowListCopyWindowInfo(
|
||||||
kCGWindowListOptionOnScreenOnly, kCGNullWindowID);
|
kCGWindowListOptionOnScreenOnly, kCGNullWindowID);
|
||||||
NSArray *filtered_arr = filter_nonzero_kcgwindowlayer_sources(arr);
|
|
||||||
|
|
||||||
[arr autorelease];
|
[arr autorelease];
|
||||||
|
|
||||||
return [filtered_arr sortedArrayUsingComparator:win_info_cmp];
|
return [arr sortedArrayUsingComparator:win_info_cmp];
|
||||||
}
|
}
|
||||||
|
|
||||||
#define WAIT_TIME_MS 500
|
#define WAIT_TIME_MS 500
|
||||||
|
|
|
@ -304,7 +304,7 @@ static bool new_stream(struct ffmpeg_mux *ffm, AVStream **stream,
|
||||||
|
|
||||||
*codec = avcodec_find_encoder(desc->id);
|
*codec = avcodec_find_encoder(desc->id);
|
||||||
if (!*codec) {
|
if (!*codec) {
|
||||||
fprintf(stderr, "Couldn't create encoder");
|
fprintf(stderr, "Couldn't create encoder\n");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -520,7 +520,7 @@ static inline int open_output_file(struct ffmpeg_mux *ffm)
|
||||||
ret = avio_open(&ffm->output->pb, ffm->params.file,
|
ret = avio_open(&ffm->output->pb, ffm->params.file,
|
||||||
AVIO_FLAG_WRITE);
|
AVIO_FLAG_WRITE);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
fprintf(stderr, "Couldn't open '%s', %s",
|
fprintf(stderr, "Couldn't open '%s', %s\n",
|
||||||
ffm->params.file, av_err2str(ret));
|
ffm->params.file, av_err2str(ret));
|
||||||
return FFM_ERROR;
|
return FFM_ERROR;
|
||||||
}
|
}
|
||||||
|
@ -529,7 +529,7 @@ static inline int open_output_file(struct ffmpeg_mux *ffm)
|
||||||
AVDictionary *dict = NULL;
|
AVDictionary *dict = NULL;
|
||||||
if ((ret = av_dict_parse_string(&dict, ffm->params.muxer_settings, "=",
|
if ((ret = av_dict_parse_string(&dict, ffm->params.muxer_settings, "=",
|
||||||
" ", 0))) {
|
" ", 0))) {
|
||||||
fprintf(stderr, "Failed to parse muxer settings: %s\n%s",
|
fprintf(stderr, "Failed to parse muxer settings: %s\n%s\n",
|
||||||
av_err2str(ret), ffm->params.muxer_settings);
|
av_err2str(ret), ffm->params.muxer_settings);
|
||||||
|
|
||||||
av_dict_free(&dict);
|
av_dict_free(&dict);
|
||||||
|
@ -548,7 +548,7 @@ static inline int open_output_file(struct ffmpeg_mux *ffm)
|
||||||
|
|
||||||
ret = avformat_write_header(ffm->output, &dict);
|
ret = avformat_write_header(ffm->output, &dict);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
fprintf(stderr, "Error opening '%s': %s", ffm->params.file,
|
fprintf(stderr, "Error opening '%s': %s\n", ffm->params.file,
|
||||||
av_err2str(ret));
|
av_err2str(ret));
|
||||||
|
|
||||||
av_dict_free(&dict);
|
av_dict_free(&dict);
|
||||||
|
@ -723,7 +723,14 @@ static inline bool ffmpeg_mux_packet(struct ffmpeg_mux *ffm, uint8_t *buf,
|
||||||
if (info->keyframe)
|
if (info->keyframe)
|
||||||
packet.flags = AV_PKT_FLAG_KEY;
|
packet.flags = AV_PKT_FLAG_KEY;
|
||||||
|
|
||||||
return av_interleaved_write_frame(ffm->output, &packet) >= 0;
|
int ret = av_interleaved_write_frame(ffm->output, &packet);
|
||||||
|
|
||||||
|
if (ret < 0) {
|
||||||
|
fprintf(stderr, "av_interleaved_write_frame failed: %s\n",
|
||||||
|
av_err2str(ret));
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret >= 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------------------- */
|
/* ------------------------------------------------------------------------- */
|
||||||
|
@ -772,7 +779,7 @@ int main(int argc, char *argv[])
|
||||||
resize_buf_resize(&rb, info.size);
|
resize_buf_resize(&rb, info.size);
|
||||||
|
|
||||||
if (safe_read(rb.buf, info.size) == info.size) {
|
if (safe_read(rb.buf, info.size) == info.size) {
|
||||||
ffmpeg_mux_packet(&ffm, rb.buf, &info);
|
fail = !ffmpeg_mux_packet(&ffm, rb.buf, &info);
|
||||||
} else {
|
} else {
|
||||||
fail = true;
|
fail = true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -440,7 +440,11 @@ static void signal_failure(struct ffmpeg_muxer *stream)
|
||||||
code = OBS_OUTPUT_UNSUPPORTED;
|
code = OBS_OUTPUT_UNSUPPORTED;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
code = OBS_OUTPUT_ERROR;
|
if (stream->is_network) {
|
||||||
|
code = OBS_OUTPUT_DISCONNECTED;
|
||||||
|
} else {
|
||||||
|
code = OBS_OUTPUT_ENCODE_ERROR;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
obs_output_signal_stop(stream->output, code);
|
obs_output_signal_stop(stream->output, code);
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
{
|
{
|
||||||
"url": "https://obsproject.com/obs2_update/rtmp-services",
|
"url": "https://obsproject.com/obs2_update/rtmp-services",
|
||||||
"version": 147,
|
"version": 148,
|
||||||
"files": [
|
"files": [
|
||||||
{
|
{
|
||||||
"name": "services.json",
|
"name": "services.json",
|
||||||
"version": 147
|
"version": 148
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -759,6 +759,10 @@
|
||||||
"name": "North America : US West",
|
"name": "North America : US West",
|
||||||
"url": "rtmp://rtmp-wsu.afreecatv.com/app"
|
"url": "rtmp://rtmp-wsu.afreecatv.com/app"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "Europe : UK",
|
||||||
|
"url": "rtmp://rtmp-uk.afreecatv.com/app"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "Asia : Singapore",
|
"name": "Asia : Singapore",
|
||||||
"url": "rtmp://rtmp-sgp.afreecatv.com/app"
|
"url": "rtmp://rtmp-sgp.afreecatv.com/app"
|
||||||
|
@ -1726,32 +1730,6 @@
|
||||||
"max audio bitrate": 160
|
"max audio bitrate": 160
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "weabook.live",
|
|
||||||
"servers": [
|
|
||||||
{
|
|
||||||
"name": "N.Virgina, US",
|
|
||||||
"url": "rtmp://us-api.weabook.live/live"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Singapore, SG",
|
|
||||||
"url": "rtmp://sg-api.weabook.live/live"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Tokyo, JP",
|
|
||||||
"url": "rtmp://jp-api.weabook.live/live"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Premium Streaming",
|
|
||||||
"url": "rtmp://premium.rtmp.weabook.live/live"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"recommended": {
|
|
||||||
"keyint": 2,
|
|
||||||
"max audio bitrate": 256,
|
|
||||||
"max video bitrate": 20480
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "Taryana - Apachat | تاریانا - آپاچت",
|
"name": "Taryana - Apachat | تاریانا - آپاچت",
|
||||||
"servers": [
|
"servers": [
|
||||||
|
|
|
@ -515,8 +515,10 @@ static void apply_video_encoder_settings(obs_data_t *settings,
|
||||||
}
|
}
|
||||||
|
|
||||||
item = json_object_get(recommended, "bframes");
|
item = json_object_get(recommended, "bframes");
|
||||||
if (json_is_integer(item))
|
if (json_is_integer(item)) {
|
||||||
obs_data_set_int(settings, "bf", 0);
|
int bframes = json_integer_value(item);
|
||||||
|
obs_data_set_int(settings, "bf", bframes);
|
||||||
|
}
|
||||||
|
|
||||||
item = json_object_get(recommended, "x264opts");
|
item = json_object_get(recommended, "x264opts");
|
||||||
if (json_is_string(item)) {
|
if (json_is_string(item)) {
|
||||||
|
|
Loading…
Reference in a new issue