Skip to content

Commit

Permalink
UI: Apply settings gathered by Pre-stream wizard
Browse files Browse the repository at this point in the history
Applies selected settings to the simple encoder setup. Use the Custom
Encoder Settings to set specific settings. Additionally, changes the
output resolution so the canvas layout is not changed possibly right
before a stream. Next to add gating so this wizard only shows in output
Simple Mode.
  • Loading branch information
JohannMG committed Oct 7, 2020
1 parent 1fca63e commit 7e3976b
Show file tree
Hide file tree
Showing 11 changed files with 245 additions and 45 deletions.
1 change: 1 addition & 0 deletions UI/common-settings.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ class CommonSettings {

/* Stream Encoder ——————————————————————————————————*/
static int GetVideoBitrateInUse(config_t *config);
static void SetAllVideoBitrates(config_t *config, int newBitrate);

private:
// Reused Strings
Expand Down
4 changes: 0 additions & 4 deletions UI/pre-stream-wizard/page-input-display.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,6 @@ QWizardPage *SettingsInputPage(StreamWizard::EncoderSettingsRequest *settings)
QWidget *formContainer = new QWidget();
QFormLayout *form = new QFormLayout(formContainer);

form->addRow("Server Url",
new QLabel(QString::fromUtf8(settings->serverUrl)));
form->addRow("Service",
new QLabel(QString::fromUtf8(settings->serviceName)));
form->addRow("Video Width",
new QLabel(QString::number(settings->videoWidth)));
form->addRow("Video Height",
Expand Down
24 changes: 17 additions & 7 deletions UI/pre-stream-wizard/page-start-prompt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,16 @@ StartPage::StartPage(Destination dest, LaunchContext launchContext,
resCurrentButton_->setChecked(true);
}
}

void StartPage::initializePage()
{
// emit defaul resolution check
if (destination_ == Destination::Facebook &&
res720Button_->isChecked()) {
emit userSelectedResolution(QSize(1280, 720));
}
}

void StartPage::createLayout()
{
QVBoxLayout *mainlayout = new QVBoxLayout(this);
Expand Down Expand Up @@ -104,17 +114,17 @@ void StartPage::createLayout()
void StartPage::connectRadioButtons()
{
connect(res720Button_, &QRadioButton::clicked, [=]() {
selectedVideoSize_ = QSize(1280, 720);
emit userSelectedResolution(selectedVideoSize_);
QSize selectedVideoSize = QSize(1280, 720);
emit userSelectedResolution(selectedVideoSize);
});
connect(res1080Button_, &QRadioButton::clicked, [=]() {
selectedVideoSize_ = QSize(1920, 1080);
emit userSelectedResolution(selectedVideoSize_);
QSize selectedVideoSize = QSize(1920, 1080);
emit userSelectedResolution(selectedVideoSize);
});
connect(resCurrentButton_, &QRadioButton::clicked, [=]() {
selectedVideoSize_ = QSize(startVideoSize_.width(),
startVideoSize_.height());
emit userSelectedResolution(selectedVideoSize_);
QSize selectedVideoSize = QSize(startVideoSize_.width(),
startVideoSize_.height());
emit userSelectedResolution(selectedVideoSize);
});
}

Expand Down
3 changes: 2 additions & 1 deletion UI/pre-stream-wizard/page-start-prompt.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ class StartPage : public QWizardPage {
StartPage(Destination dest, LaunchContext launchContext,
QSize videoSize, QWidget *parent = nullptr);

void initializePage() override;

signals:
// emitted selected resolution from start page radio buttons
void userSelectedResolution(QSize newVideoSize);
Expand All @@ -28,7 +30,6 @@ class StartPage : public QWizardPage {
QSize startVideoSize_;

// Selected settings
QSize selectedVideoSize_;
QRadioButton *res720Button_;
QRadioButton *res1080Button_;
QRadioButton *resCurrentButton_;
Expand Down
2 changes: 0 additions & 2 deletions UI/pre-stream-wizard/pre-stream-current-settings.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,6 @@ struct EncoderSettingsRequest {
//// Stream
StreamProtocol protocol; // Expandable but only supports RTMPS for now
VideoType videoType; // LIVE or VOD (but always live for OBS)
char *serverUrl;
char *serviceName;

///// Video Settings
int videoWidth;
Expand Down
6 changes: 6 additions & 0 deletions UI/pre-stream-wizard/pre-stream-wizard.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ void PreStreamWizard::requestSettings()
connect(fbProvider,
&FacebookEncoderSettingsProvider::returnErrorDescription,
this, &PreStreamWizard::providerError);

fbProvider->setEncoderRequest(currentSettings_);
fbProvider->run();

Expand Down Expand Up @@ -132,6 +133,11 @@ void PreStreamWizard::onPageChanged(int id)

case Page_Complete:
setButtons(FinishOnly);
if (newSettingsMap_ != nullptr && !newSettingsMap_.isNull()) {
// ToDo: messaging in edge case this could be empty
// and still make it here?
emit applySettings(newSettingsMap_);
};
break;

case Page_Error:
Expand Down
12 changes: 0 additions & 12 deletions UI/pre-stream-wizard/pre-stream-wizard.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,18 +56,6 @@ class PreStreamWizard : public QWizard {
void setButtons(ButtonLayout layout);

signals:
// User left the wizard with intention to continue streaming
void userSkippedWizard(void);

// User canceled, also canceling intent to stream.
void userAbortedStream(void);

// User ready to start stream
// If newSettings is not null, they should be applied before stream
// If newSettings is null, user or wizard did not opt to apply changes.
void
startStreamWithSettings(QSharedPointer<SettingsMap> newSettingsOrNull);

// Apply settings, don't start stream. e.g., is configuring from settings
void applySettings(QSharedPointer<SettingsMap> newSettings);

Expand Down
185 changes: 177 additions & 8 deletions UI/streaming-settings-util.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
#include "common-settings.hpp"
#include <util/config-file.h>

#include <QPair>

/*
We are detecting the stream settings so if they're using a large canvas but
already have the rescaler on, they will be streaming correctly.
Expand Down Expand Up @@ -32,8 +34,7 @@ void UpdateStreamingResolution(int *resolutionXY, bool isRescaled,
};

QSharedPointer<StreamWizard::EncoderSettingsRequest>
StreamingSettingsUtility::makeEncoderSettingsFromCurrentState(
config_t *config, obs_data_t *settings)
StreamingSettingsUtility::makeEncoderSettingsFromCurrentState(config_t *config)
{
QSharedPointer<StreamWizard::EncoderSettingsRequest> currentSettings(
new StreamWizard::EncoderSettingsRequest());
Expand All @@ -43,12 +44,6 @@ StreamingSettingsUtility::makeEncoderSettingsFromCurrentState(
currentSettings->videoType = StreamWizard::VideoType::live;
// only live and rmpts is supported for now
currentSettings->protocol = StreamWizard::StreamProtocol::rtmps;

currentSettings->serverUrl =
bstrdup(obs_data_get_string(settings, "server"));
currentSettings->serviceName =
bstrdup(obs_data_get_string(settings, "service"));

/* Video */
bool isRescaled = config_get_bool(config, "AdvOut", "Rescale");
int resolutionXY[2] = {0, 0};
Expand All @@ -73,3 +68,177 @@ StreamingSettingsUtility::makeEncoderSettingsFromCurrentState(

return currentSettings;
};

/*
* StreamWizard::SettingsMap is sparse in that it wont have all keys
* as well, the user can opt out of settings being applied.
* The map looks like [ SettingsResponseKeys : QPair<QVariant, bool> ]
* AKA [KEY : SetttingPair<Setting_Value_Variant, User_Wants_Setting_Bool> ]
* if the key is available, it means the wizard provider added a value for it
* but the bool in the QPair is false if the user selected in the wizard not to
* apply the setting. A case would be we suggest a 720p stream but the user
* knows their account supports 1080 so disabled the setting from applying.
* Returns TRUE is map contrains something for the key and it is marked true
*/
bool CheckInMapAndSelected(StreamWizard::SettingsMap *map, const char *key)
{
if (!map->contains(key)) {
return false;
}
const QPair<QVariant, bool> settingPair = map->value(key);
return settingPair.second;
}

// Helper Functions for ::applyWizardSettings
int intFromMap(StreamWizard::SettingsMap *map, const char *key)
{
QPair<QVariant, bool> settingPair = map->value(key);
QVariant data = settingPair.first;
return data.toInt();
}

QString stringFromMap(StreamWizard::SettingsMap *map, const char *key)
{
QPair<QVariant, bool> settingPair = map->value(key);
QVariant data = settingPair.first;
return data.toString();
}

double doubleFromMap(StreamWizard::SettingsMap *map, const char *key)
{
QPair<QVariant, bool> settingPair = map->value(key);
QVariant data = settingPair.first;
return data.toDouble();
}

bool boolFromMap(StreamWizard::SettingsMap *map, const char *key)
{
QPair<QVariant, bool> settingPair = map->value(key);
QVariant data = settingPair.first;
return data.toBool();
}

/*
* Given a settings map [ SettingsResponseKeys : QPair<QVariant, bool> ] apply
* settings that are in the sparse map as well selected by the user (which is
* marked by the bool in the pair).
* Apply to Basic encoder settings.
* Possible later goal: autoconfig advanced settings too
*/
void StreamingSettingsUtility::applyWizardSettings(
QSharedPointer<StreamWizard::SettingsMap> newSettings, config_t *config)
{

if (newSettings == nullptr || newSettings.isNull())
return;

// scope to function usage
using namespace StreamWizard;

SettingsMap *map = newSettings.data();

QStringList x264SettingList;
config_set_bool(config, "SimpleOutput", "UseAdvanced", true);

// Resolution must have both
if (CheckInMapAndSelected(map, SettingsResponseKeys.videoHeight) &&
CheckInMapAndSelected(map, SettingsResponseKeys.videoWidth)) {

int canvasX = intFromMap(map, SettingsResponseKeys.videoWidth);
int canvasY = intFromMap(map, SettingsResponseKeys.videoHeight);
config_set_uint(config, "Video", "OutputCX", canvasX);
config_set_uint(config, "Video", "OutputCY", canvasY);
}

//TODO: FPS is hacky but covers all integer and standard drop frame cases
if (CheckInMapAndSelected(map, SettingsResponseKeys.framerate)) {
double currentFPS = CommonSettings::GetConfigFPSDouble(config);
double newFPS =
doubleFromMap(map, SettingsResponseKeys.framerate);
if (abs(currentFPS - newFPS) >
0.001) { // Only change if different
if (abs(floor(newFPS) - newFPS) >
0.01) { // Is a drop-frame FPS
int num = ceil(newFPS) * 1000;
int den = 1001;
config_set_uint(config, "Video", "FPSType",
2); // Fraction
config_set_uint(config, "Video", "FPSNum", num);
config_set_uint(config, "Video", "FPSDen", den);
} else { // Is integer FPS
config_set_uint(config, "Video", "FPSType",
1); // Integer
config_set_uint(config, "Video", "FPSInt",
(int)floor(newFPS));
}
}
}

if (CheckInMapAndSelected(map, SettingsResponseKeys.videoBitrate)) {
int newBitrate =
intFromMap(map, SettingsResponseKeys.videoBitrate);
config_set_int(config, "SimpleOutput", "VBitrate", newBitrate);
}

if (CheckInMapAndSelected(map, SettingsResponseKeys.h264Profile)) {
QString profile =
stringFromMap(map, SettingsResponseKeys.h264Profile);
profile = profile.toLower();
x264SettingList.append("profile=" + profile);
}

if (CheckInMapAndSelected(map, SettingsResponseKeys.h264Level)) {
QString levelString =
stringFromMap(map, SettingsResponseKeys.h264Level);
x264SettingList.append("level=" + levelString);
}

if (CheckInMapAndSelected(map, SettingsResponseKeys.gopSizeInFrames)) {
int gopSize =
intFromMap(map, SettingsResponseKeys.gopSizeInFrames);
x264SettingList.append("keyint=" + QString::number(gopSize));
}

if (CheckInMapAndSelected(map, SettingsResponseKeys.gopType)) {
QString gopType =
stringFromMap(map, SettingsResponseKeys.gopType);
x264SettingList.append("slice_mode=" + gopType);
}

if (CheckInMapAndSelected(map, SettingsResponseKeys.gopClosed)) {
bool gopClose =
boolFromMap(map, SettingsResponseKeys.gopClosed);
if (gopClose) {
x264SettingList.append("open_gop=0");
} else {
x264SettingList.append("open_gop=1");
}
}

if (CheckInMapAndSelected(map, SettingsResponseKeys.gopBFrames)) {
int bFrames = intFromMap(map, SettingsResponseKeys.gopBFrames);
x264SettingList.append("bframes=" + QString::number(bFrames));
}

if (CheckInMapAndSelected(map, SettingsResponseKeys.gopRefFrames)) {
int refFrames =
intFromMap(map, SettingsResponseKeys.gopRefFrames);
x264SettingList.append("ref=" + QString::number(refFrames));
}

// SettingsResponseKeys.streamRateControlMode defaults to CBR in Simple
// encoder mode. Can add later for advanced panel.

if (CheckInMapAndSelected(map, SettingsResponseKeys.streamBufferSize)) {
int bufferSize =
intFromMap(map, SettingsResponseKeys.streamBufferSize);
x264SettingList.append("bufsize=" +
QString::number(bufferSize));
}

QString x264String = x264SettingList.join(" ");
const char *x264_c_String = x264String.toStdString().c_str();
config_set_string(config, "SimpleOutput", "x264Settings",
x264_c_String);
};
7 changes: 5 additions & 2 deletions UI/streaming-settings-util.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ class StreamingSettingsUtility : public QObject {
public:
// Uses current settings in OBS
static QSharedPointer<StreamWizard::EncoderSettingsRequest>
makeEncoderSettingsFromCurrentState(config_t *config,
obs_data_t *settings);
makeEncoderSettingsFromCurrentState(config_t *config);

static void applyWizardSettings(
QSharedPointer<StreamWizard::SettingsMap> newSettings,
config_t *config);
};
Loading

0 comments on commit 7e3976b

Please sign in to comment.