Prechádzať zdrojové kódy

UI: Add support for QSV encoder to simple output

jp9000 9 rokov pred
rodič
commit
60ec56b2c6

+ 1 - 0
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"

+ 26 - 54
obs/forms/OBSBasicSettings.ui

@@ -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">

+ 93 - 19
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);
 	}
 }
 

+ 2 - 0
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);

+ 1 - 0
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
 

+ 91 - 2
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)
 

+ 6 - 0
obs/window-basic-settings.hpp

@@ -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);