From 60ec56b2c6caaed3ec102a77fb4ded5e18db9390 Mon Sep 17 00:00:00 2001 From: jp9000 Date: Mon, 18 Apr 2016 00:56:51 -0700 Subject: [PATCH] UI: Add support for QSV encoder to simple output --- obs/data/locale/en-US.ini | 1 + obs/forms/OBSBasicSettings.ui | 80 +++++++-------------- obs/window-basic-main-outputs.cpp | 112 +++++++++++++++++++++++++----- obs/window-basic-main.cpp | 2 + obs/window-basic-main.hpp | 1 + obs/window-basic-settings.cpp | 93 ++++++++++++++++++++++++- obs/window-basic-settings.hpp | 6 ++ 7 files changed, 220 insertions(+), 75 deletions(-) diff --git a/obs/data/locale/en-US.ini b/obs/data/locale/en-US.ini index 790074e3e..2eafbacc6 100644 --- a/obs/data/locale/en-US.ini +++ b/obs/data/locale/en-US.ini @@ -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" diff --git a/obs/forms/OBSBasicSettings.ui b/obs/forms/OBSBasicSettings.ui index 93aa25e93..736b75e9f 100644 --- a/obs/forms/OBSBasicSettings.ui +++ b/obs/forms/OBSBasicSettings.ui @@ -539,7 +539,7 @@ - + Basic.Settings.Output.AudioBitrate @@ -549,7 +549,7 @@ - + 8 @@ -611,7 +611,7 @@ - + Basic.Settings.Output.Advanced @@ -621,51 +621,10 @@ - - - - - ultrafast - - - - - superfast - - - - - veryfast - - - - - faster - - - - - fast - - - - - medium - - - - - slow - - - - - slower - - - + + - + true @@ -678,7 +637,7 @@ - + Basic.Settings.Output.CustomEncoderSettings @@ -688,16 +647,29 @@ - + - + Basic.Settings.Output.EnforceBitrate + + + + + + + Basic.Settings.Output.Encoder + + + simpleOutRecEncoder + + + @@ -2525,8 +2497,8 @@ 0 0 - 98 - 28 + 80 + 16 @@ -2891,8 +2863,8 @@ 0 0 - 525 - 383 + 559 + 563 diff --git a/obs/window-basic-main-outputs.cpp b/obs/window-basic-main-outputs.cpp index 577eaa51c..83e5cbe19 100644 --- a/obs/window-basic-main-outputs.cpp +++ b/obs/window-basic-main-outputs.cpp @@ -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); } } diff --git a/obs/window-basic-main.cpp b/obs/window-basic-main.cpp index b1bf17055..aa2089fdf 100644 --- a/obs/window-basic-main.cpp +++ b/obs/window-basic-main.cpp @@ -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); diff --git a/obs/window-basic-main.hpp b/obs/window-basic-main.hpp index 7d3dc6773..e82e80bc8 100644 --- a/obs/window-basic-main.hpp +++ b/obs/window-basic-main.hpp @@ -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 diff --git a/obs/window-basic-settings.cpp b/obs/window-basic-settings.cpp index 93bd10b4e..3c8ba9070 100644 --- a/obs/window-basic-settings.cpp +++ b/obs/window-basic-settings.cpp @@ -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) diff --git a/obs/window-basic-settings.hpp b/obs/window-basic-settings.hpp index 00be30837..b7f02fbd7 100644 --- a/obs/window-basic-settings.hpp +++ b/obs/window-basic-settings.hpp @@ -108,6 +108,9 @@ private: QPointer advOutRecWarning; QPointer simpleOutRecWarning; + QString curPreset; + QString curQSVPreset; + using AudioSource_t = std::tuple, QPointer, @@ -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);