UI: Add support for QSV encoder to simple output

This commit is contained in:
jp9000 2016-04-18 00:56:51 -07:00
parent 81313dfd35
commit 60ec56b2c6
7 changed files with 220 additions and 75 deletions

View File

@ -389,6 +389,7 @@ Basic.Settings.Output.Simple.Warn.Lossless="Warning: Lossless quality generates
Basic.Settings.Output.Simple.Warn.Lossless.Msg="Are you sure you want to use lossless quality?"
Basic.Settings.Output.Simple.Warn.Lossless.Title="Lossless quality warning!"
Basic.Settings.Output.Simple.Encoder.Software="Software (x264)"
Basic.Settings.Output.Simple.Encoder.Hardware.QSV="Hardware (QSV)"
Basic.Settings.Output.Simple.Encoder.SoftwareLowCPU="Software (x264 low CPU usage preset, increases file size)"
Basic.Settings.Output.VideoBitrate="Video Bitrate"
Basic.Settings.Output.AudioBitrate="Audio Bitrate"

View File

@ -539,7 +539,7 @@
</property>
</widget>
</item>
<item row="1" column="0">
<item row="2" column="0">
<widget class="QLabel" name="label_20">
<property name="text">
<string>Basic.Settings.Output.AudioBitrate</string>
@ -549,7 +549,7 @@
</property>
</widget>
</item>
<item row="1" column="1">
<item row="2" column="1">
<widget class="QComboBox" name="simpleOutputABitrate">
<property name="currentIndex">
<number>8</number>
@ -611,7 +611,7 @@
</item>
</widget>
</item>
<item row="2" column="1">
<item row="3" column="1">
<widget class="QCheckBox" name="simpleOutAdvanced">
<property name="text">
<string>Basic.Settings.Output.Advanced</string>
@ -621,51 +621,10 @@
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QComboBox" name="simpleOutPreset">
<item>
<property name="text">
<string notr="true">ultrafast</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">superfast</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">veryfast</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">faster</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">fast</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">medium</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">slow</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">slower</string>
</property>
</item>
</widget>
<item row="5" column="1">
<widget class="QComboBox" name="simpleOutPreset"/>
</item>
<item row="4" column="0">
<item row="5" column="0">
<widget class="QLabel" name="label_24">
<property name="enabled">
<bool>true</bool>
@ -678,7 +637,7 @@
</property>
</widget>
</item>
<item row="5" column="0">
<item row="6" column="0">
<widget class="QLabel" name="label_23">
<property name="text">
<string>Basic.Settings.Output.CustomEncoderSettings</string>
@ -688,16 +647,29 @@
</property>
</widget>
</item>
<item row="5" column="1">
<item row="6" column="1">
<widget class="QLineEdit" name="simpleOutCustom"/>
</item>
<item row="3" column="1">
<item row="4" column="1">
<widget class="QCheckBox" name="simpleOutEnforce">
<property name="text">
<string>Basic.Settings.Output.EnforceBitrate</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="simpleOutStrEncoder"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="simpleOutRecEncoderLabel_2">
<property name="text">
<string>Basic.Settings.Output.Encoder</string>
</property>
<property name="buddy">
<cstring>simpleOutRecEncoder</cstring>
</property>
</widget>
</item>
</layout>
</widget>
</item>
@ -2525,8 +2497,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>98</width>
<height>28</height>
<width>80</width>
<height>16</height>
</rect>
</property>
</widget>
@ -2891,8 +2863,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>525</width>
<height>383</height>
<width>559</width>
<height>563</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout_16">

View File

@ -153,6 +153,7 @@ struct SimpleOutput : BasicOutputHandler {
int CalcCRF(int crf);
void UpdateRecordingSettings_x264_crf(int crf);
void UpdateRecordingSettings_qsv11(int crf);
void UpdateRecordingSettings();
void UpdateRecordingAudioSettings();
virtual void Update() override;
@ -160,10 +161,12 @@ struct SimpleOutput : BasicOutputHandler {
void SetupOutputs();
int GetAudioBitrate() const;
void LoadRecordingPreset_x264();
void LoadRecordingPreset_h264(const char *encoder);
void LoadRecordingPreset_Lossless();
void LoadRecordingPreset();
void LoadStreamingPreset_h264(const char *encoder);
virtual bool StartStreaming(obs_service_t *service) override;
virtual bool StartRecording() override;
virtual void StopStreaming() override;
@ -191,17 +194,22 @@ void SimpleOutput::LoadRecordingPreset_Lossless()
obs_data_release(settings);
}
void SimpleOutput::LoadRecordingPreset_x264()
void SimpleOutput::LoadRecordingPreset_h264(const char *encoderId)
{
h264Recording = obs_video_encoder_create("obs_x264",
h264Recording = obs_video_encoder_create(encoderId,
"simple_h264_recording", nullptr, nullptr);
if (!h264Recording)
throw "Failed to create h264 recording encoder (simple output)";
obs_encoder_release(h264Recording);
}
if (!CreateAACEncoder(aacRecording, aacRecEncID, 192,
"simple_aac_recording", 0))
throw "Failed to create aac recording encoder (simple output)";
void SimpleOutput::LoadStreamingPreset_h264(const char *encoderId)
{
h264Streaming = obs_video_encoder_create(encoderId,
"simple_h264_stream", nullptr, nullptr);
if (!h264Streaming)
throw "Failed to create h264 streaming encoder (simple output)";
obs_encoder_release(h264Streaming);
}
void SimpleOutput::LoadRecordingPreset()
@ -228,9 +236,22 @@ void SimpleOutput::LoadRecordingPreset()
return;
} else {
lowCPUx264 = strcmp(encoder, SIMPLE_ENCODER_X264_LOWCPU) == 0;
LoadRecordingPreset_x264();
lowCPUx264 = false;
if (strcmp(encoder, SIMPLE_ENCODER_X264) == 0) {
LoadRecordingPreset_h264("obs_x264");
} else if (strcmp(encoder, SIMPLE_ENCODER_X264_LOWCPU) == 0) {
LoadRecordingPreset_h264("obs_x264");
lowCPUx264 = true;
} else if (strcmp(encoder, SIMPLE_ENCODER_QSV) == 0) {
LoadRecordingPreset_h264("obs_qsv11");
}
usingRecordingPreset = true;
if (!CreateAACEncoder(aacRecording, aacRecEncID, 192,
"simple_aac_recording", 0))
throw "Failed to create aac recording encoder "
"(simple output)";
}
}
@ -242,11 +263,12 @@ SimpleOutput::SimpleOutput(OBSBasic *main_) : BasicOutputHandler(main_)
throw "Failed to create stream output (simple output)";
obs_output_release(streamOutput);
h264Streaming = obs_video_encoder_create("obs_x264",
"simple_h264_stream", nullptr, nullptr);
if (!h264Streaming)
throw "Failed to create h264 streaming encoder (simple output)";
obs_encoder_release(h264Streaming);
const char *encoder = config_get_string(main->Config(), "SimpleOutput",
"StreamEncoder");
if (strcmp(encoder, SIMPLE_ENCODER_QSV) == 0)
LoadStreamingPreset_h264("obs_qsv11");
else
LoadStreamingPreset_h264("obs_x264");
if (!CreateAACEncoder(aacStreaming, aacStreamEncID, GetAudioBitrate(),
"simple_aac", 0))
@ -299,10 +321,19 @@ void SimpleOutput::Update()
"UseAdvanced");
bool enforceBitrate = config_get_bool(main->Config(), "SimpleOutput",
"EnforceBitrate");
const char *preset = config_get_string(main->Config(),
"SimpleOutput", "Preset");
const char *custom = config_get_string(main->Config(),
"SimpleOutput", "x264Settings");
const char *encoder = config_get_string(main->Config(), "SimpleOutput",
"StreamEncoder");
const char *presetType;
const char *preset;
if (strcmp(encoder, SIMPLE_ENCODER_QSV) == 0)
presetType = "QSVPreset";
else
presetType = "Preset";
preset = config_get_string(main->Config(), "SimpleOutput", presetType);
obs_data_set_int(h264Settings, "bitrate", videoBitrate);
@ -384,13 +415,56 @@ void SimpleOutput::UpdateRecordingSettings_x264_crf(int crf)
obs_data_release(settings);
}
static bool icq_available(obs_encoder_t *encoder)
{
obs_properties_t *props = obs_encoder_properties(encoder);
obs_property_t *p = obs_properties_get(props, "rate_control");
bool icq_found = false;
size_t num = obs_property_list_item_count(p);
for (size_t i = 0; i < num; i++) {
const char *val = obs_property_list_item_string(p, i);
if (strcmp(val, "ICQ_LA") == 0) {
icq_found = true;
break;
}
}
obs_properties_destroy(props);
return icq_found;
}
void SimpleOutput::UpdateRecordingSettings_qsv11(int crf)
{
bool icq = icq_available(h264Recording);
obs_data_t *settings = obs_data_create();
obs_data_set_string(settings, "profile", "high");
if (icq) {
obs_data_set_string(settings, "rate_control", "LA_ICQ");
obs_data_set_int(settings, "icq_quality", crf);
} else {
obs_data_set_string(settings, "rate_control", "CQP");
obs_data_set_int(settings, "qpi", crf);
obs_data_set_int(settings, "qpp", crf);
obs_data_set_int(settings, "qpb", crf);
}
obs_encoder_update(h264Recording, settings);
obs_data_release(settings);
}
void SimpleOutput::UpdateRecordingSettings()
{
int crf = CalcCRF((videoQuality == "HQ") ? 16 : 23);
if (astrcmp_n(videoEncoder.c_str(), "x264", 4) == 0) {
if (videoQuality == "Small")
UpdateRecordingSettings_x264_crf(CalcCRF(23));
else if (videoQuality == "HQ")
UpdateRecordingSettings_x264_crf(CalcCRF(16));
UpdateRecordingSettings_x264_crf(crf);
} else if (videoEncoder == SIMPLE_ENCODER_QSV) {
UpdateRecordingSettings_qsv11(crf);
}
}

View File

@ -738,6 +738,8 @@ bool OBSBasic::InitBasicConfigDefaults()
"flv");
config_set_default_uint (basicConfig, "SimpleOutput", "VBitrate",
2500);
config_set_default_string(basicConfig, "SimpleOutput", "StreamEncoder",
SIMPLE_ENCODER_X264);
config_set_default_uint (basicConfig, "SimpleOutput", "ABitrate", 160);
config_set_default_bool (basicConfig, "SimpleOutput", "UseAdvanced",
false);

View File

@ -49,6 +49,7 @@ class QNetworkReply;
#define SIMPLE_ENCODER_X264 "x264"
#define SIMPLE_ENCODER_X264_LOWCPU "x264_lowcpu"
#define SIMPLE_ENCODER_QSV "qsv"
#define PREVIEW_EDGE_SIZE 10

View File

@ -282,6 +282,7 @@ OBSBasicSettings::OBSBasicSettings(QWidget *parent)
HookWidget(ui->simpleNoSpace, CHECK_CHANGED, OUTPUTS_CHANGED);
HookWidget(ui->simpleOutRecFormat, COMBO_CHANGED, OUTPUTS_CHANGED);
HookWidget(ui->simpleOutputVBitrate, SCROLL_CHANGED, OUTPUTS_CHANGED);
HookWidget(ui->simpleOutStrEncoder, COMBO_CHANGED, OUTPUTS_CHANGED);
HookWidget(ui->simpleOutputABitrate, COMBO_CHANGED, OUTPUTS_CHANGED);
HookWidget(ui->simpleOutAdvanced, CHECK_CHANGED, OUTPUTS_CHANGED);
HookWidget(ui->simpleOutEnforce, CHECK_CHANGED, OUTPUTS_CHANGED);
@ -470,10 +471,14 @@ OBSBasicSettings::OBSBasicSettings(QWidget *parent)
"hotkey_unregister", ReloadHotkeysIgnore, this);
FillSimpleRecordingValues();
FillSimpleStreamingValues();
connect(ui->simpleOutRecQuality, SIGNAL(currentIndexChanged(int)),
this, SLOT(SimpleRecordingQualityChanged()));
connect(ui->simpleOutRecQuality, SIGNAL(currentIndexChanged(int)),
this, SLOT(SimpleRecordingQualityLosslessWarning(int)));
connect(ui->simpleOutStrEncoder, SIGNAL(currentIndexChanged(int)),
this, SLOT(SimpleStreamingEncoderChanged()));
connect(ui->simpleOutRecEncoder, SIGNAL(currentIndexChanged(int)),
this, SLOT(SimpleRecordingEncoderChanged()));
connect(ui->simpleOutputVBitrate, SIGNAL(valueChanged(int)),
@ -1118,6 +1123,8 @@ void OBSBasicSettings::LoadSimpleOutputSettings()
"RecFormat");
int videoBitrate = config_get_uint(main->Config(), "SimpleOutput",
"VBitrate");
const char *streamEnc = config_get_string(main->Config(), "SimpleOutput",
"StreamEncoder");
int audioBitrate = config_get_uint(main->Config(), "SimpleOutput",
"ABitrate");
bool advanced = config_get_bool(main->Config(), "SimpleOutput",
@ -1126,6 +1133,8 @@ void OBSBasicSettings::LoadSimpleOutputSettings()
"EnforceBitrate");
const char *preset = config_get_string(main->Config(), "SimpleOutput",
"Preset");
const char *qsvPreset = config_get_string(main->Config(), "SimpleOutput",
"QSVPreset");
const char *custom = config_get_string(main->Config(), "SimpleOutput",
"x264Settings");
const char *recQual = config_get_string(main->Config(), "SimpleOutput",
@ -1135,6 +1144,9 @@ void OBSBasicSettings::LoadSimpleOutputSettings()
const char *muxCustom = config_get_string(main->Config(),
"SimpleOutput", "MuxerCustom");
curPreset = preset;
curQSVPreset = qsvPreset;
audioBitrate = FindClosestAvailableAACBitrate(audioBitrate);
ui->simpleOutputPath->setText(path);
@ -1148,7 +1160,6 @@ void OBSBasicSettings::LoadSimpleOutputSettings()
std::to_string(audioBitrate).c_str());
ui->simpleOutAdvanced->setChecked(advanced);
ui->simpleOutPreset->setCurrentText(preset);
ui->simpleOutEnforce->setChecked(enforceBitrate);
ui->simpleOutCustom->setText(custom);
@ -1156,11 +1167,17 @@ void OBSBasicSettings::LoadSimpleOutputSettings()
if (idx == -1) idx = 0;
ui->simpleOutRecQuality->setCurrentIndex(idx);
idx = ui->simpleOutStrEncoder->findData(QString(streamEnc));
if (idx == -1) idx = 0;
ui->simpleOutStrEncoder->setCurrentIndex(idx);
idx = ui->simpleOutRecEncoder->findData(QString(recEnc));
if (idx == -1) idx = 0;
ui->simpleOutRecEncoder->setCurrentIndex(idx);
ui->simpleOutMuxCustom->setText(muxCustom);
SimpleStreamingEncoderChanged();
}
void OBSBasicSettings::LoadAdvOutputStreamingSettings()
@ -2320,14 +2337,23 @@ void OBSBasicSettings::SaveOutputSettings()
config_set_string(main->Config(), "Output", "Mode",
OutputModeFromIdx(ui->outputMode->currentIndex()));
QString encoder = ui->simpleOutStrEncoder->currentData().toString();
const char *presetType;
if (encoder == SIMPLE_ENCODER_QSV)
presetType = "QSVPreset";
else
presetType = "Preset";
SaveSpinBox(ui->simpleOutputVBitrate, "SimpleOutput", "VBitrate");
SaveComboData(ui->simpleOutStrEncoder, "SimpleOutput", "StreamEncoder");
SaveCombo(ui->simpleOutputABitrate, "SimpleOutput", "ABitrate");
SaveEdit(ui->simpleOutputPath, "SimpleOutput", "FilePath");
SaveCheckBox(ui->simpleNoSpace, "SimpleOutput", "FileNameWithoutSpace");
SaveCombo(ui->simpleOutRecFormat, "SimpleOutput", "RecFormat");
SaveCheckBox(ui->simpleOutAdvanced, "SimpleOutput", "UseAdvanced");
SaveCheckBox(ui->simpleOutEnforce, "SimpleOutput", "EnforceBitrate");
SaveCombo(ui->simpleOutPreset, "SimpleOutput", "Preset");
SaveComboData(ui->simpleOutPreset, "SimpleOutput", presetType);
SaveEdit(ui->simpleOutCustom, "SimpleOutput", "x264Settings");
SaveComboData(ui->simpleOutRecQuality, "SimpleOutput", "RecQuality");
SaveComboData(ui->simpleOutRecEncoder, "SimpleOutput", "RecEncoder");
@ -3042,6 +3068,18 @@ void OBSBasicSettings::UpdateStreamDelayEstimate()
UpdateAdvOutStreamDelayEstimate();
}
static bool EncoderAvailable(const char *encoder)
{
const char *val;
int i = 0;
while (obs_enum_encoder_types(i++, &val))
if (strcmp(val, encoder) == 0)
return true;
return false;
}
void OBSBasicSettings::FillSimpleRecordingValues()
{
#define ADD_QUALITY(str) \
@ -3062,7 +3100,22 @@ void OBSBasicSettings::FillSimpleRecordingValues()
ui->simpleOutRecEncoder->addItem(
ENCODER_STR("SoftwareLowCPU"),
QString(SIMPLE_ENCODER_X264_LOWCPU));
if (EncoderAvailable("obs_qsv11"))
ui->simpleOutRecEncoder->addItem(
ENCODER_STR("Hardware.QSV"),
QString(SIMPLE_ENCODER_QSV));
#undef ADD_QUALITY
}
void OBSBasicSettings::FillSimpleStreamingValues()
{
ui->simpleOutStrEncoder->addItem(
ENCODER_STR("Software"),
QString(SIMPLE_ENCODER_X264));
if (EncoderAvailable("obs_qsv11"))
ui->simpleOutStrEncoder->addItem(
ENCODER_STR("Hardware.QSV"),
QString(SIMPLE_ENCODER_QSV));
#undef ENCODER_STR
}
@ -3081,6 +3134,42 @@ void OBSBasicSettings::SimpleRecordingQualityChanged()
SimpleRecordingEncoderChanged();
}
void OBSBasicSettings::SimpleStreamingEncoderChanged()
{
QString encoder = ui->simpleOutStrEncoder->currentData().toString();
QString preset;
const char *defaultPreset = nullptr;
ui->simpleOutPreset->clear();
if (encoder == SIMPLE_ENCODER_QSV) {
ui->simpleOutPreset->addItem("speed", "speed");
ui->simpleOutPreset->addItem("balanced", "balanced");
ui->simpleOutPreset->addItem("quality", "quality");
defaultPreset = "balanced";
preset = curQSVPreset;
} else {
ui->simpleOutPreset->addItem("ultrafast", "ultrafast");
ui->simpleOutPreset->addItem("superfast", "superfast");
ui->simpleOutPreset->addItem("veryfast", "veryfast");
ui->simpleOutPreset->addItem("faster", "faster");
ui->simpleOutPreset->addItem("fast", "fast");
ui->simpleOutPreset->addItem("medium", "medium");
ui->simpleOutPreset->addItem("slow", "slow");
ui->simpleOutPreset->addItem("slower", "slower");
defaultPreset = "veryfast";
preset = curPreset;
}
int idx = ui->simpleOutPreset->findData(QVariant(preset));
if (idx == -1)
idx = ui->simpleOutPreset->findData(QVariant(defaultPreset));
ui->simpleOutPreset->setCurrentIndex(idx);
}
#define SIMPLE_OUTPUT_WARNING(str) \
QTStr("Basic.Settings.Output.Simple.Warn." str)

View File

@ -108,6 +108,9 @@ private:
QPointer<QLabel> advOutRecWarning;
QPointer<QLabel> simpleOutRecWarning;
QString curPreset;
QString curQSVPreset;
using AudioSource_t =
std::tuple<OBSWeakSource,
QPointer<QCheckBox>, QPointer<QSpinBox>,
@ -231,6 +234,7 @@ private:
void UpdateAdvOutStreamDelayEstimate();
void FillSimpleRecordingValues();
void FillSimpleStreamingValues();
void RecalcOutputResPixels(const char *resText);
@ -281,6 +285,8 @@ private slots:
void SimpleRecordingEncoderChanged();
void SimpleRecordingQualityLosslessWarning(int idx);
void SimpleStreamingEncoderChanged();
protected:
virtual void closeEvent(QCloseEvent *event);