public inbox for git-commits@fedoraproject.org
help / color / mirror / Atom feed
* [rpms/obs-studio] epel9-next: Rebase to 30.0.0~beta3
@ 2026-07-20 19:39 Neal Gompa
  0 siblings, 0 replies; only message in thread
From: Neal Gompa @ 2026-07-20 19:39 UTC (permalink / raw)
  To: git-commits

A new commit has been pushed.

Repo   : rpms/obs-studio
Branch : epel9-next
Commit : da7c27338e50c22ed586c8d215a43eee1f31a604
Author : Neal Gompa <ngompa@fedoraproject.org>
Date   : 2023-09-11T16:45:17-04:00
Stats  : +1308/-1313 in 14 file(s)
URL    : https://src.fedoraproject.org/rpms/obs-studio/c/da7c27338e50c22ed586c8d215a43eee1f31a604?branch=epel9-next

Log:
Rebase to 30.0.0~beta3

---
diff --git a/0001-UI-Consistently-reference-the-software-H264-encoder-.patch b/0001-UI-Consistently-reference-the-software-H264-encoder-.patch
deleted file mode 100644
index e976f5c..0000000
--- a/0001-UI-Consistently-reference-the-software-H264-encoder-.patch
+++ /dev/null
@@ -1,104 +0,0 @@
-From 04d3a21c6e72cd5574f7333adf548012d912c1ee Mon Sep 17 00:00:00 2001
-From: Neal Gompa <neal@gompa.dev>
-Date: Sat, 7 Jan 2023 23:15:13 -0500
-Subject: [PATCH 1/3] UI: Consistently reference the software H264 encoder
- properly
-
-The code here assumes that the only software encoder is the x264-based
-H.264 encoder. That may not always remain true. This change adjusts
-the encoder string to indicate that it's an H.264 encoder from x264.
----
- UI/data/locale/en-US.ini             | 4 ++--
- UI/window-basic-auto-config-test.cpp | 6 +++---
- UI/window-basic-settings-stream.cpp  | 2 +-
- UI/window-basic-settings.cpp         | 7 ++++---
- 4 files changed, 10 insertions(+), 9 deletions(-)
-
-diff --git a/UI/data/locale/en-US.ini b/UI/data/locale/en-US.ini
-index 4c03aa7db..e44d99660 100644
---- a/UI/data/locale/en-US.ini
-+++ b/UI/data/locale/en-US.ini
-@@ -980,7 +980,7 @@ Basic.Settings.Output.Simple.Warn.Encoder="Warning: Recording with a software en
- Basic.Settings.Output.Simple.Warn.Lossless="Warning: Lossless quality generates tremendously large file sizes! Lossless quality can use upward of 7 gigabytes of disk space per minute at high resolutions and framerates. Lossless is not recommended for long recordings unless you have a very large amount of disk space available."
- 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.Software.X264.H264="Software (x264)"
- Basic.Settings.Output.Simple.Encoder.Hardware.QSV.H264="Hardware (QSV, H.264)"
- Basic.Settings.Output.Simple.Encoder.Hardware.QSV.AV1="Hardware (QSV, AV1)"
- Basic.Settings.Output.Simple.Encoder.Hardware.AMD.H264="Hardware (AMD, H.264)"
-@@ -991,7 +991,7 @@ Basic.Settings.Output.Simple.Encoder.Hardware.NVENC.AV1="Hardware (NVENC, AV1)"
- Basic.Settings.Output.Simple.Encoder.Hardware.NVENC.HEVC="Hardware (NVENC, HEVC)"
- Basic.Settings.Output.Simple.Encoder.Hardware.Apple.H264="Hardware (Apple, H.264)"
- Basic.Settings.Output.Simple.Encoder.Hardware.Apple.HEVC="Hardware (Apple, HEVC)"
--Basic.Settings.Output.Simple.Encoder.SoftwareLowCPU="Software (x264 low CPU usage preset, increases file size)"
-+Basic.Settings.Output.Simple.Encoder.SoftwareLowCPU.X264.H264="Software (x264 low CPU usage preset, increases file size)"
- Basic.Settings.Output.Simple.Codec.AAC="AAC"
- Basic.Settings.Output.Simple.Codec.AAC.Default="AAC (Default)"
- Basic.Settings.Output.Simple.Codec.Opus="Opus"
-diff --git a/UI/window-basic-auto-config-test.cpp b/UI/window-basic-auto-config-test.cpp
-index 2d89d7347..09979c031 100644
---- a/UI/window-basic-auto-config-test.cpp
-+++ b/UI/window-basic-auto-config-test.cpp
-@@ -993,7 +993,7 @@ void AutoConfigTestPage::TestRecordingEncoderThread()
- }
- 
- #define ENCODER_TEXT(x) "Basic.Settings.Output.Simple.Encoder." x
--#define ENCODER_SOFTWARE ENCODER_TEXT("Software")
-+#define ENCODER_X264 ENCODER_TEXT("Software.X264.H264")
- #define ENCODER_NVENC ENCODER_TEXT("Hardware.NVENC.H264")
- #define ENCODER_QSV ENCODER_TEXT("Hardware.QSV.H264")
- #define ENCODER_AMD ENCODER_TEXT("Hardware.AMD.H264")
-@@ -1033,7 +1033,7 @@ void AutoConfigTestPage::FinalizeResults()
- 	auto encName = [](AutoConfig::Encoder enc) -> QString {
- 		switch (enc) {
- 		case AutoConfig::Encoder::x264:
--			return QTStr(ENCODER_SOFTWARE);
-+			return QTStr(ENCODER_X264);
- 		case AutoConfig::Encoder::NVENC:
- 			return QTStr(ENCODER_NVENC);
- 		case AutoConfig::Encoder::QSV:
-@@ -1046,7 +1046,7 @@ void AutoConfigTestPage::FinalizeResults()
- 			return QTStr(QUALITY_SAME);
- 		}
- 
--		return QTStr(ENCODER_SOFTWARE);
-+		return QTStr(ENCODER_X264);
- 	};
- 
- 	auto newLabel = [this](const char *str) -> QLabel * {
-diff --git a/UI/window-basic-settings-stream.cpp b/UI/window-basic-settings-stream.cpp
-index f6e0817a0..b056938e7 100644
---- a/UI/window-basic-settings-stream.cpp
-+++ b/UI/window-basic-settings-stream.cpp
-@@ -1585,7 +1585,7 @@ void OBSBasicSettings::ResetEncoders(bool streamOnly)
- 
- #define ENCODER_STR(str) QTStr("Basic.Settings.Output.Simple.Encoder." str)
- 
--	ui->simpleOutStrEncoder->addItem(ENCODER_STR("Software"),
-+	ui->simpleOutStrEncoder->addItem(ENCODER_STR("Software.X264.H264"),
- 					 QString(SIMPLE_ENCODER_X264));
- 	if (service_supports_encoder(vcodecs, "obs_qsv11"))
- 		ui->simpleOutStrEncoder->addItem(
-diff --git a/UI/window-basic-settings.cpp b/UI/window-basic-settings.cpp
-index fb170bfc1..48bb4bac6 100644
---- a/UI/window-basic-settings.cpp
-+++ b/UI/window-basic-settings.cpp
-@@ -5286,10 +5286,11 @@ void OBSBasicSettings::FillSimpleRecordingValues()
- 	ADD_QUALITY("HQ");
- 	ADD_QUALITY("Lossless");
- 
--	ui->simpleOutRecEncoder->addItem(ENCODER_STR("Software"),
-+	ui->simpleOutRecEncoder->addItem(ENCODER_STR("Software.X264.H264"),
- 					 QString(SIMPLE_ENCODER_X264));
--	ui->simpleOutRecEncoder->addItem(ENCODER_STR("SoftwareLowCPU"),
--					 QString(SIMPLE_ENCODER_X264_LOWCPU));
-+	ui->simpleOutRecEncoder->addItem(
-+		ENCODER_STR("SoftwareLowCPU.X264.H264"),
-+		QString(SIMPLE_ENCODER_X264_LOWCPU));
- 	if (EncoderAvailable("obs_qsv11"))
- 		ui->simpleOutRecEncoder->addItem(
- 			ENCODER_STR("Hardware.QSV.H264"),
--- 
-2.39.2
-

diff --git a/0002-obs-ffmpeg-Add-initial-support-for-the-OpenH264-H.26.patch b/0002-obs-ffmpeg-Add-initial-support-for-the-OpenH264-H.26.patch
deleted file mode 100644
index 0a80a79..0000000
--- a/0002-obs-ffmpeg-Add-initial-support-for-the-OpenH264-H.26.patch
+++ /dev/null
@@ -1,346 +0,0 @@
-From 4517d8d8bb4c43af1f5b757773a5f9550bd23d37 Mon Sep 17 00:00:00 2001
-From: Neal Gompa <neal@gompa.dev>
-Date: Sun, 26 Mar 2023 06:06:31 -0400
-Subject: [PATCH 2/3] obs-ffmpeg: Add initial support for the OpenH264 H.264
- software codec
-
-This allows users to leverage the OpenH264 codec from Cisco to encode
-H.264 video content. It is significantly reduced in capability from
-alternatives, but it does the job.
-
-This also provides a framework for adding support for other H.264
-software codecs provided through FFmpeg.
----
- plugins/obs-ffmpeg/CMakeLists.txt        |   1 +
- plugins/obs-ffmpeg/cmake/legacy.cmake    |   1 +
- plugins/obs-ffmpeg/data/locale/en-US.ini |   3 +
- plugins/obs-ffmpeg/obs-ffmpeg-h264.c     | 260 +++++++++++++++++++++++
- plugins/obs-ffmpeg/obs-ffmpeg.c          |   2 +
- 5 files changed, 267 insertions(+)
- create mode 100644 plugins/obs-ffmpeg/obs-ffmpeg-h264.c
-
-diff --git a/plugins/obs-ffmpeg/CMakeLists.txt b/plugins/obs-ffmpeg/CMakeLists.txt
-index 3eba00932..f97622c22 100644
---- a/plugins/obs-ffmpeg/CMakeLists.txt
-+++ b/plugins/obs-ffmpeg/CMakeLists.txt
-@@ -34,6 +34,7 @@ target_sources(
-           obs-ffmpeg-video-encoders.c
-           obs-ffmpeg-audio-encoders.c
-           obs-ffmpeg-av1.c
-+          obs-ffmpeg-h264.c
-           obs-ffmpeg-nvenc.c
-           obs-ffmpeg-output.c
-           obs-ffmpeg-mux.c
-diff --git a/plugins/obs-ffmpeg/cmake/legacy.cmake b/plugins/obs-ffmpeg/cmake/legacy.cmake
-index 5540676ea..62f2cc7a1 100644
---- a/plugins/obs-ffmpeg/cmake/legacy.cmake
-+++ b/plugins/obs-ffmpeg/cmake/legacy.cmake
-@@ -40,6 +40,7 @@ target_sources(
-           obs-ffmpeg-video-encoders.c
-           obs-ffmpeg-audio-encoders.c
-           obs-ffmpeg-av1.c
-+          obs-ffmpeg-h264.c
-           obs-ffmpeg-nvenc.c
-           obs-ffmpeg-output.c
-           obs-ffmpeg-mux.c
-diff --git a/plugins/obs-ffmpeg/data/locale/en-US.ini b/plugins/obs-ffmpeg/data/locale/en-US.ini
-index 55bbe919d..0363ed82b 100644
---- a/plugins/obs-ffmpeg/data/locale/en-US.ini
-+++ b/plugins/obs-ffmpeg/data/locale/en-US.ini
-@@ -109,4 +109,7 @@ NVENC.CheckDrivers="Try installing the latest <a href=\"https://obsproject.com/g
- 
- AV1.8bitUnsupportedHdr="OBS does not support 8-bit output of Rec. 2100."
- 
-+H264.UnsupportedVideoFormat="Only video formats using 8-bit color are supported."
-+H264.UnsupportedColorSpace="Only the Rec. 709 color space is supported."
-+
- ReconnectDelayTime="Reconnect Delay"
-diff --git a/plugins/obs-ffmpeg/obs-ffmpeg-h264.c b/plugins/obs-ffmpeg/obs-ffmpeg-h264.c
-new file mode 100644
-index 000000000..179a61ccf
---- /dev/null
-+++ b/plugins/obs-ffmpeg/obs-ffmpeg-h264.c
-@@ -0,0 +1,260 @@
-+/******************************************************************************
-+    Copyright (C) 2023 by Neal Gompa <neal@gompa.dev>
-+    Partly derived from obs-ffmpeg-av1.c by Hugh Bailey <obs.jim@gmail.com>
-+
-+    This program is free software: you can redistribute it and/or modify
-+    it under the terms of the GNU General Public License as published by
-+    the Free Software Foundation, either version 2 of the License, or
-+    (at your option) any later version.
-+
-+    This program is distributed in the hope that it will be useful,
-+    but WITHOUT ANY WARRANTY; without even the implied warranty of
-+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+    GNU General Public License for more details.
-+
-+    You should have received a copy of the GNU General Public License
-+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
-+******************************************************************************/
-+
-+#include "obs-ffmpeg-video-encoders.h"
-+
-+#define do_log(level, format, ...)                   \
-+	blog(level, "[H.264 encoder: '%s'] " format, \
-+	     obs_encoder_get_name(enc->ffve.encoder), ##__VA_ARGS__)
-+
-+#define error(format, ...) do_log(LOG_ERROR, format, ##__VA_ARGS__)
-+#define warn(format, ...) do_log(LOG_WARNING, format, ##__VA_ARGS__)
-+#define info(format, ...) do_log(LOG_INFO, format, ##__VA_ARGS__)
-+#define debug(format, ...) do_log(LOG_DEBUG, format, ##__VA_ARGS__)
-+
-+enum h264_encoder_type {
-+	H264_ENCODER_TYPE_OH264,
-+};
-+
-+struct h264_encoder {
-+	struct ffmpeg_video_encoder ffve;
-+	enum h264_encoder_type type;
-+
-+	DARRAY(uint8_t) header;
-+};
-+
-+static const char *oh264_getname(void *unused)
-+{
-+	UNUSED_PARAMETER(unused);
-+	return "OpenH264";
-+}
-+
-+static void h264_video_info(void *data, struct video_scale_info *info)
-+{
-+	UNUSED_PARAMETER(data);
-+
-+	// OpenH264 only supports I420
-+	info->format = VIDEO_FORMAT_I420;
-+}
-+
-+static bool h264_update(struct h264_encoder *enc, obs_data_t *settings)
-+{
-+	const char *profile = obs_data_get_string(settings, "profile");
-+	int bitrate = (int)obs_data_get_int(settings, "bitrate");
-+	int keyint_sec = 0;              // This is not supported by OpenH264
-+	const char *rc_mode = "quality"; // We only want to use quality mode
-+	int allow_skip_frames = 1;       // This is required for quality mode
-+
-+	video_t *video = obs_encoder_video(enc->ffve.encoder);
-+	const struct video_output_info *voi = video_output_get_info(video);
-+	struct video_scale_info info;
-+
-+	info.format = voi->format;
-+	info.colorspace = voi->colorspace;
-+	info.range = voi->range;
-+
-+	enc->ffve.context->thread_count = 0;
-+
-+	h264_video_info(enc, &info);
-+
-+	av_opt_set(enc->ffve.context->priv_data, "rc_mode", rc_mode, 0);
-+	av_opt_set(enc->ffve.context->priv_data, "profile", profile, 0);
-+	av_opt_set_int(enc->ffve.context->priv_data, "allow_skip_frames",
-+		       allow_skip_frames, 0);
-+
-+	const char *ffmpeg_opts = obs_data_get_string(settings, "ffmpeg_opts");
-+	ffmpeg_video_encoder_update(&enc->ffve, bitrate, keyint_sec, voi, &info,
-+				    ffmpeg_opts);
-+	info("settings:\n"
-+	     "\tencoder:      %s\n"
-+	     "\trc_mode:      %s\n"
-+	     "\tbitrate:      %d\n"
-+	     "\tprofile:      %s\n"
-+	     "\twidth:        %d\n"
-+	     "\theight:       %d\n"
-+	     "\tffmpeg opts:  %s\n",
-+	     enc->ffve.enc_name, rc_mode, bitrate, profile,
-+	     enc->ffve.context->width, enc->ffve.height, ffmpeg_opts);
-+
-+	enc->ffve.context->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
-+	return ffmpeg_video_encoder_init_codec(&enc->ffve);
-+}
-+
-+static void h264_destroy(void *data)
-+{
-+	struct h264_encoder *enc = data;
-+
-+	ffmpeg_video_encoder_free(&enc->ffve);
-+	da_free(enc->header);
-+	bfree(enc);
-+}
-+
-+static void on_first_packet(void *data, AVPacket *pkt, struct darray *da)
-+{
-+	struct h264_encoder *enc = data;
-+
-+	da_copy_array(enc->header, enc->ffve.context->extradata,
-+		      enc->ffve.context->extradata_size);
-+
-+	darray_copy_array(1, da, pkt->data, pkt->size);
-+}
-+
-+static void *h264_create_internal(obs_data_t *settings, obs_encoder_t *encoder,
-+				  const char *enc_lib, const char *enc_name)
-+{
-+	video_t *video = obs_encoder_video(encoder);
-+	const struct video_output_info *voi = video_output_get_info(video);
-+
-+	switch (voi->format) {
-+	// planar 4:2:0 formats
-+	case VIDEO_FORMAT_I420: // three-plane
-+	case VIDEO_FORMAT_NV12: // two-plane, luma and packed chroma
-+	// packed 4:2:2 formats
-+	case VIDEO_FORMAT_YVYU:
-+	case VIDEO_FORMAT_YUY2: // YUYV
-+	case VIDEO_FORMAT_UYVY:
-+	// packed uncompressed formats
-+	case VIDEO_FORMAT_RGBA:
-+	case VIDEO_FORMAT_BGRA:
-+	case VIDEO_FORMAT_BGRX:
-+	case VIDEO_FORMAT_BGR3:
-+	case VIDEO_FORMAT_Y800: // grayscale
-+	// planar 4:4:4
-+	case VIDEO_FORMAT_I444:
-+	// planar 4:2:2
-+	case VIDEO_FORMAT_I422:
-+	// planar 4:2:0 with alpha
-+	case VIDEO_FORMAT_I40A:
-+	// planar 4:2:2 with alpha
-+	case VIDEO_FORMAT_I42A:
-+	// planar 4:4:4 with alpha
-+	case VIDEO_FORMAT_YUVA:
-+	// packed 4:4:4 with alpha
-+	case VIDEO_FORMAT_AYUV:
-+		break;
-+	default:; // Make the compiler do the right thing
-+		const char *const text =
-+			obs_module_text("H264.UnsupportedVideoFormat");
-+		obs_encoder_set_last_error(encoder, text);
-+		blog(LOG_ERROR, "[H.264 encoder] %s", text);
-+		return NULL;
-+	}
-+
-+	switch (voi->colorspace) {
-+	case VIDEO_CS_DEFAULT:
-+	case VIDEO_CS_709:
-+		break;
-+	default:; // Make the compiler do the right thing
-+		const char *const text =
-+			obs_module_text("H264.UnsupportedColorSpace");
-+		obs_encoder_set_last_error(encoder, text);
-+		blog(LOG_ERROR, "[H.264 encoder] %s", text);
-+		return NULL;
-+	}
-+
-+	struct h264_encoder *enc = bzalloc(sizeof(*enc));
-+
-+	if (strcmp(enc_lib, "libopenh264") == 0)
-+		enc->type = H264_ENCODER_TYPE_OH264;
-+
-+	if (!ffmpeg_video_encoder_init(&enc->ffve, enc, encoder, enc_lib, NULL,
-+				       enc_name, NULL, on_first_packet))
-+		goto fail;
-+	if (!h264_update(enc, settings))
-+		goto fail;
-+
-+	return enc;
-+
-+fail:
-+	h264_destroy(enc);
-+	return NULL;
-+}
-+
-+static void *oh264_create(obs_data_t *settings, obs_encoder_t *encoder)
-+{
-+	return h264_create_internal(settings, encoder, "libopenh264",
-+				    "OpenH264");
-+}
-+
-+static bool h264_encode(void *data, struct encoder_frame *frame,
-+			struct encoder_packet *packet, bool *received_packet)
-+{
-+	struct h264_encoder *enc = data;
-+	return ffmpeg_video_encode(&enc->ffve, frame, packet, received_packet);
-+}
-+
-+void h264_defaults(obs_data_t *settings)
-+{
-+	obs_data_set_default_int(settings, "bitrate", 2500);
-+	obs_data_set_default_string(settings, "profile", "main");
-+}
-+
-+obs_properties_t *h264_properties(enum h264_encoder_type type)
-+{
-+	UNUSED_PARAMETER(type); // Only one encoder right now...
-+	obs_properties_t *props = obs_properties_create();
-+	obs_property_t *p;
-+
-+	p = obs_properties_add_list(props, "profile",
-+				    obs_module_text("Profile"),
-+				    OBS_COMBO_TYPE_LIST,
-+				    OBS_COMBO_FORMAT_STRING);
-+	obs_property_list_add_string(p, "constrained_baseline",
-+				     "constrained_baseline");
-+	obs_property_list_add_string(p, "main", "main");
-+	obs_property_list_add_string(p, "high", "high");
-+
-+	p = obs_properties_add_int(props, "bitrate", obs_module_text("Bitrate"),
-+				   50, 300000, 50);
-+	obs_property_int_set_suffix(p, " Kbps");
-+
-+	obs_properties_add_text(props, "ffmpeg_opts",
-+				obs_module_text("FFmpegOpts"),
-+				OBS_TEXT_DEFAULT);
-+
-+	return props;
-+}
-+
-+obs_properties_t *oh264_properties(void *unused)
-+{
-+	UNUSED_PARAMETER(unused);
-+	return h264_properties(H264_ENCODER_TYPE_OH264);
-+}
-+
-+static bool h264_extra_data(void *data, uint8_t **extra_data, size_t *size)
-+{
-+	struct h264_encoder *enc = data;
-+
-+	*extra_data = enc->header.array;
-+	*size = enc->header.num;
-+	return true;
-+}
-+
-+struct obs_encoder_info oh264_encoder_info = {
-+	.id = "ffmpeg_openh264",
-+	.type = OBS_ENCODER_VIDEO,
-+	.codec = "h264",
-+	.get_name = oh264_getname,
-+	.create = oh264_create,
-+	.destroy = h264_destroy,
-+	.encode = h264_encode,
-+	.get_defaults = h264_defaults,
-+	.get_properties = oh264_properties,
-+	.get_extra_data = h264_extra_data,
-+	.get_video_info = h264_video_info,
-+};
-diff --git a/plugins/obs-ffmpeg/obs-ffmpeg.c b/plugins/obs-ffmpeg/obs-ffmpeg.c
-index da0b2c2b4..a01a729c8 100644
---- a/plugins/obs-ffmpeg/obs-ffmpeg.c
-+++ b/plugins/obs-ffmpeg/obs-ffmpeg.c
-@@ -39,6 +39,7 @@ extern struct obs_encoder_info pcm24_encoder_info;
- extern struct obs_encoder_info pcm32_encoder_info;
- extern struct obs_encoder_info alac_encoder_info;
- extern struct obs_encoder_info flac_encoder_info;
-+extern struct obs_encoder_info oh264_encoder_info;
- extern struct obs_encoder_info h264_nvenc_encoder_info;
- #ifdef ENABLE_HEVC
- extern struct obs_encoder_info hevc_nvenc_encoder_info;
-@@ -387,6 +388,7 @@ bool obs_module_load(void)
- 	obs_register_output(&ffmpeg_hls_muxer);
- 	obs_register_output(&replay_buffer);
- 	obs_register_encoder(&aac_encoder_info);
-+	register_encoder_if_available(&oh264_encoder_info, "libopenh264");
- 	register_encoder_if_available(&svt_av1_encoder_info, "libsvtav1");
- 	register_encoder_if_available(&aom_av1_encoder_info, "libaom-av1");
- 	obs_register_encoder(&opus_encoder_info);
--- 
-2.39.2
-

diff --git a/0003-UI-Add-support-for-OpenH264-as-the-worst-case-fallba.patch b/0003-UI-Add-support-for-OpenH264-as-the-worst-case-fallba.patch
deleted file mode 100644
index cb52514..0000000
--- a/0003-UI-Add-support-for-OpenH264-as-the-worst-case-fallba.patch
+++ /dev/null
@@ -1,545 +0,0 @@
-From 30f84455969071ff9aa826a44438a0402dd15123 Mon Sep 17 00:00:00 2001
-From: Neal Gompa <neal@gompa.dev>
-Date: Tue, 28 Mar 2023 05:08:49 -0400
-Subject: [PATCH 3/3] UI: Add support for OpenH264 as the worst-case fallback
-
-OpenH264 exists as the codec of last resort, so it is implemented
-such that it is only used as the software codec if x264 is not
-available.
----
- UI/data/locale/en-US.ini             |  1 +
- UI/window-basic-auto-config-test.cpp | 50 +++++++++++++++++++---------
- UI/window-basic-auto-config.cpp      | 15 ++++++++-
- UI/window-basic-auto-config.hpp      |  3 ++
- UI/window-basic-main-outputs.cpp     |  6 ++--
- UI/window-basic-main-profiles.cpp    | 34 +++++++++++--------
- UI/window-basic-main.cpp             | 20 +++++++----
- UI/window-basic-main.hpp             |  3 +-
- UI/window-basic-settings-stream.cpp  | 16 ++++++---
- UI/window-basic-settings.cpp         | 23 ++++++++++---
- 10 files changed, 123 insertions(+), 48 deletions(-)
-
-diff --git a/UI/data/locale/en-US.ini b/UI/data/locale/en-US.ini
-index e44d99660..a5ba5d661 100644
---- a/UI/data/locale/en-US.ini
-+++ b/UI/data/locale/en-US.ini
-@@ -980,6 +980,7 @@ Basic.Settings.Output.Simple.Warn.Encoder="Warning: Recording with a software en
- Basic.Settings.Output.Simple.Warn.Lossless="Warning: Lossless quality generates tremendously large file sizes! Lossless quality can use upward of 7 gigabytes of disk space per minute at high resolutions and framerates. Lossless is not recommended for long recordings unless you have a very large amount of disk space available."
- 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.OpenH264.H264="Software (OpenH264)"
- Basic.Settings.Output.Simple.Encoder.Software.X264.H264="Software (x264)"
- Basic.Settings.Output.Simple.Encoder.Hardware.QSV.H264="Hardware (QSV, H.264)"
- Basic.Settings.Output.Simple.Encoder.Hardware.QSV.AV1="Hardware (QSV, AV1)"
-diff --git a/UI/window-basic-auto-config-test.cpp b/UI/window-basic-auto-config-test.cpp
-index 09979c031..c791c8b8b 100644
---- a/UI/window-basic-auto-config-test.cpp
-+++ b/UI/window-basic-auto-config-test.cpp
-@@ -199,7 +199,8 @@ void AutoConfigTestPage::TestBandwidthThread()
- 						   : "rtmp_common";
- 
- 	OBSEncoderAutoRelease vencoder = obs_video_encoder_create(
--		"obs_x264", "test_x264", nullptr, nullptr);
-+		(wiz->x264Available ? "obs_x264" : "ffmpeg_openh264"),
-+		"test_h264", nullptr, nullptr);
- 	OBSEncoderAutoRelease aencoder = obs_audio_encoder_create(
- 		"ffmpeg_aac", "test_aac", nullptr, 0, nullptr);
- 	OBSServiceAutoRelease service = obs_service_create(
-@@ -238,10 +239,11 @@ void AutoConfigTestPage::TestBandwidthThread()
- 	obs_data_set_string(service_settings, "key", key.c_str());
- 
- 	obs_data_set_int(vencoder_settings, "bitrate", wiz->startingBitrate);
--	obs_data_set_string(vencoder_settings, "rate_control", "CBR");
--	obs_data_set_string(vencoder_settings, "preset", "veryfast");
--	obs_data_set_int(vencoder_settings, "keyint_sec", 2);
--
-+	if (wiz->x264Available) {
-+		obs_data_set_string(vencoder_settings, "rate_control", "CBR");
-+		obs_data_set_string(vencoder_settings, "preset", "veryfast");
-+		obs_data_set_int(vencoder_settings, "keyint_sec", 2);
-+	}
- 	obs_data_set_int(aencoder_settings, "bitrate", 32);
- 
- 	OBSBasic *main = reinterpret_cast<OBSBasic *>(App()->GetMainWindow());
-@@ -567,7 +569,8 @@ bool AutoConfigTestPage::TestSoftwareEncoding()
- 	/* create obs objects                 */
- 
- 	OBSEncoderAutoRelease vencoder = obs_video_encoder_create(
--		"obs_x264", "test_x264", nullptr, nullptr);
-+		(wiz->x264Available ? "obs_x264" : "ffmpeg_openh264"),
-+		"test_h264", nullptr, nullptr);
- 	OBSEncoderAutoRelease aencoder = obs_audio_encoder_create(
- 		"ffmpeg_aac", "test_aac", nullptr, 0, nullptr);
- 	OBSOutputAutoRelease output =
-@@ -581,17 +584,25 @@ bool AutoConfigTestPage::TestSoftwareEncoding()
- 	obs_data_set_int(aencoder_settings, "bitrate", 32);
- 
- 	if (wiz->type != AutoConfig::Type::Recording) {
--		obs_data_set_int(vencoder_settings, "keyint_sec", 2);
-+		if (wiz->x264Available) {
-+			obs_data_set_int(vencoder_settings, "keyint_sec", 2);
-+			obs_data_set_string(vencoder_settings, "rate_control",
-+					    "CBR");
-+			obs_data_set_string(vencoder_settings, "preset",
-+					    "veryfast");
-+		}
- 		obs_data_set_int(vencoder_settings, "bitrate",
- 				 wiz->idealBitrate);
--		obs_data_set_string(vencoder_settings, "rate_control", "CBR");
- 		obs_data_set_string(vencoder_settings, "profile", "main");
--		obs_data_set_string(vencoder_settings, "preset", "veryfast");
- 	} else {
--		obs_data_set_int(vencoder_settings, "crf", 20);
--		obs_data_set_string(vencoder_settings, "rate_control", "CRF");
-+		if (wiz->x264Available) {
-+			obs_data_set_int(vencoder_settings, "crf", 20);
-+			obs_data_set_string(vencoder_settings, "rate_control",
-+					    "CRF");
-+			obs_data_set_string(vencoder_settings, "preset",
-+					    "veryfast");
-+		}
- 		obs_data_set_string(vencoder_settings, "profile", "high");
--		obs_data_set_string(vencoder_settings, "preset", "veryfast");
- 	}
- 
- 	/* -----------------------------------*/
-@@ -944,7 +955,10 @@ void AutoConfigTestPage::TestStreamEncoderThread()
- 		else
- 			wiz->streamingEncoder = AutoConfig::Encoder::AMD;
- 	} else {
--		wiz->streamingEncoder = AutoConfig::Encoder::x264;
-+		if (wiz->x264Available)
-+			wiz->streamingEncoder = AutoConfig::Encoder::x264;
-+		else
-+			wiz->streamingEncoder = AutoConfig::Encoder::OpenH264;
- 	}
- 
- 	if (preferHardware && !softwareTested && wiz->hardwareEncodingAvailable)
-@@ -979,7 +993,10 @@ void AutoConfigTestPage::TestRecordingEncoderThread()
- 		else
- 			wiz->recordingEncoder = AutoConfig::Encoder::AMD;
- 	} else {
--		wiz->recordingEncoder = AutoConfig::Encoder::x264;
-+		if (wiz->x264Available)
-+			wiz->streamingEncoder = AutoConfig::Encoder::x264;
-+		else
-+			wiz->streamingEncoder = AutoConfig::Encoder::OpenH264;
- 	}
- 
- 	if (wiz->recordingEncoder != AutoConfig::Encoder::NVENC) {
-@@ -993,6 +1010,7 @@ void AutoConfigTestPage::TestRecordingEncoderThread()
- }
- 
- #define ENCODER_TEXT(x) "Basic.Settings.Output.Simple.Encoder." x
-+#define ENCODER_OPENH264 ENCODER_TEXT("Software.OpenH264.H264")
- #define ENCODER_X264 ENCODER_TEXT("Software.X264.H264")
- #define ENCODER_NVENC ENCODER_TEXT("Hardware.NVENC.H264")
- #define ENCODER_QSV ENCODER_TEXT("Hardware.QSV.H264")
-@@ -1032,6 +1050,8 @@ void AutoConfigTestPage::FinalizeResults()
- 
- 	auto encName = [](AutoConfig::Encoder enc) -> QString {
- 		switch (enc) {
-+		case AutoConfig::Encoder::OpenH264:
-+			return QTStr(ENCODER_OPENH264);
- 		case AutoConfig::Encoder::x264:
- 			return QTStr(ENCODER_X264);
- 		case AutoConfig::Encoder::NVENC:
-@@ -1046,7 +1066,7 @@ void AutoConfigTestPage::FinalizeResults()
- 			return QTStr(QUALITY_SAME);
- 		}
- 
--		return QTStr(ENCODER_X264);
-+		return QTStr(ENCODER_OPENH264);
- 	};
- 
- 	auto newLabel = [this](const char *str) -> QLabel * {
-diff --git a/UI/window-basic-auto-config.cpp b/UI/window-basic-auto-config.cpp
-index 3e9c36685..eace18067 100644
---- a/UI/window-basic-auto-config.cpp
-+++ b/UI/window-basic-auto-config.cpp
-@@ -961,6 +961,7 @@ AutoConfig::AutoConfig(QWidget *parent) : QWizard(parent)
- 	streamPage->ui->bitrate->setValue(bitrate);
- 	streamPage->ServiceChanged();
- 
-+	TestSoftwareEncoding();
- 	TestHardwareEncoding();
- 	if (!hardwareEncodingAvailable) {
- 		delete streamPage->ui->preferHardware;
-@@ -989,6 +990,16 @@ AutoConfig::~AutoConfig()
- 	EnableThreadedMessageBoxes(false);
- }
- 
-+void AutoConfig::TestSoftwareEncoding()
-+{
-+	size_t idx = 0;
-+	const char *id;
-+	while (obs_enum_encoder_types(idx++, &id)) {
-+		if (strcmp(id, "obs_x264") == 0)
-+			x264Available = true;
-+	}
-+}
-+
- void AutoConfig::TestHardwareEncoding()
- {
- 	size_t idx = 0;
-@@ -1061,8 +1072,10 @@ inline const char *AutoConfig::GetEncoderId(Encoder enc)
- 		return SIMPLE_ENCODER_AMD;
- 	case Encoder::Apple:
- 		return SIMPLE_ENCODER_APPLE_H264;
--	default:
-+	case Encoder::x264:
- 		return SIMPLE_ENCODER_X264;
-+	default:
-+		return SIMPLE_ENCODER_OPENH264;
- 	}
- };
- 
-diff --git a/UI/window-basic-auto-config.hpp b/UI/window-basic-auto-config.hpp
-index eb50701ff..e581791dd 100644
---- a/UI/window-basic-auto-config.hpp
-+++ b/UI/window-basic-auto-config.hpp
-@@ -43,6 +43,7 @@ class AutoConfig : public QWizard {
- 	};
- 
- 	enum class Encoder {
-+		OpenH264,
- 		x264,
- 		NVENC,
- 		QSV,
-@@ -91,6 +92,7 @@ class AutoConfig : public QWizard {
- 	bool qsvAvailable = false;
- 	bool vceAvailable = false;
- 	bool appleAvailable = false;
-+	bool x264Available = false;
- 
- 	int startingBitrate = 2500;
- 	bool customServer = false;
-@@ -106,6 +108,7 @@ class AutoConfig : public QWizard {
- 	int specificFPSNum = 0;
- 	int specificFPSDen = 0;
- 
-+	void TestSoftwareEncoding();
- 	void TestHardwareEncoding();
- 	bool CanTestServer(const char *server);
- 
-diff --git a/UI/window-basic-main-outputs.cpp b/UI/window-basic-main-outputs.cpp
-index 737ab966d..a4df630c4 100644
---- a/UI/window-basic-main-outputs.cpp
-+++ b/UI/window-basic-main-outputs.cpp
-@@ -515,7 +515,9 @@ void SimpleOutput::LoadStreamingPreset_Lossy(const char *encoderId)
- /* mistakes have been made to lead us to this. */
- const char *get_simple_output_encoder(const char *encoder)
- {
--	if (strcmp(encoder, SIMPLE_ENCODER_X264) == 0) {
-+	if (strcmp(encoder, SIMPLE_ENCODER_OPENH264) == 0) {
-+		return "ffmpeg_openh264";
-+	} else if (strcmp(encoder, SIMPLE_ENCODER_X264) == 0) {
- 		return "obs_x264";
- 	} else if (strcmp(encoder, SIMPLE_ENCODER_X264_LOWCPU) == 0) {
- 		return "obs_x264";
-@@ -549,7 +551,7 @@ const char *get_simple_output_encoder(const char *encoder)
- #endif
- 	}
- 
--	return "obs_x264";
-+	return "ffmpeg_openh264";
- }
- 
- void SimpleOutput::LoadRecordingPreset()
-diff --git a/UI/window-basic-main-profiles.cpp b/UI/window-basic-main-profiles.cpp
-index 4941359ea..1f3ffdc1d 100644
---- a/UI/window-basic-main-profiles.cpp
-+++ b/UI/window-basic-main-profiles.cpp
-@@ -794,7 +794,7 @@ void OBSBasic::ChangeProfile()
- 
- 	Auth::Load();
- 
--	CheckForSimpleModeX264Fallback();
-+	CheckForSimpleModeH264Fallback();
- 
- 	blog(LOG_INFO, "Switched to profile '%s' (%s)", newName, newDir);
- 	blog(LOG_INFO, "------------------------------------------------");
-@@ -815,12 +815,13 @@ void OBSBasic::ChangeProfile()
- 	}
- }
- 
--void OBSBasic::CheckForSimpleModeX264Fallback()
-+void OBSBasic::CheckForSimpleModeH264Fallback()
- {
- 	const char *curStreamEncoder =
- 		config_get_string(basicConfig, "SimpleOutput", "StreamEncoder");
- 	const char *curRecEncoder =
- 		config_get_string(basicConfig, "SimpleOutput", "RecEncoder");
-+	bool x264_supported = false;
- 	bool qsv_supported = false;
- 	bool qsv_av1_supported = false;
- 	bool amd_supported = false;
-@@ -837,7 +838,9 @@ void OBSBasic::CheckForSimpleModeX264Fallback()
- 	const char *id;
- 
- 	while (obs_enum_encoder_types(idx++, &id)) {
--		if (strcmp(id, "amd_amf_h264") == 0)
-+		if (strcmp(id, "obs_x264") == 0)
-+			x264_supported = true;
-+		else if (strcmp(id, "amd_amf_h264") == 0)
- 			amd_supported = true;
- 		else if (strcmp(id, "obs_qsv11") == 0)
- 			qsv_supported = true;
-@@ -865,68 +868,73 @@ void OBSBasic::CheckForSimpleModeX264Fallback()
- #endif
- 	}
- 
-+	// Check to see whether x264 is available
-+	const char *fallback_encoder_name = (x264_supported
-+						     ? SIMPLE_ENCODER_X264
-+						     : SIMPLE_ENCODER_OPENH264);
-+
- 	auto CheckEncoder = [&](const char *&name) {
- 		if (strcmp(name, SIMPLE_ENCODER_QSV) == 0) {
- 			if (!qsv_supported) {
- 				changed = true;
--				name = SIMPLE_ENCODER_X264;
-+				name = fallback_encoder_name;
- 				return false;
- 			}
- 		} else if (strcmp(name, SIMPLE_ENCODER_QSV_AV1) == 0) {
- 			if (!qsv_av1_supported) {
- 				changed = true;
--				name = SIMPLE_ENCODER_X264;
-+				name = fallback_encoder_name;
- 				return false;
- 			}
- 		} else if (strcmp(name, SIMPLE_ENCODER_NVENC) == 0) {
- 			if (!nve_supported) {
- 				changed = true;
--				name = SIMPLE_ENCODER_X264;
-+				name = fallback_encoder_name;
- 				return false;
- 			}
- 		} else if (strcmp(name, SIMPLE_ENCODER_NVENC_AV1) == 0) {
- 			if (!nve_supported) {
- 				changed = true;
--				name = SIMPLE_ENCODER_X264;
-+				name = fallback_encoder_name;
- 				return false;
- 			}
- #ifdef ENABLE_HEVC
- 		} else if (strcmp(name, SIMPLE_ENCODER_AMD_HEVC) == 0) {
- 			if (!amd_hevc_supported) {
- 				changed = true;
--				name = SIMPLE_ENCODER_X264;
-+				name = fallback_encoder_name;
- 				return false;
- 			}
- 		} else if (strcmp(name, SIMPLE_ENCODER_NVENC_HEVC) == 0) {
- 			if (!nve_hevc_supported) {
- 				changed = true;
--				name = SIMPLE_ENCODER_X264;
-+				name = fallback_encoder_name;
- 				return false;
- 			}
- #endif
- 		} else if (strcmp(name, SIMPLE_ENCODER_AMD) == 0) {
- 			if (!amd_supported) {
- 				changed = true;
--				name = SIMPLE_ENCODER_X264;
-+				name = fallback_encoder_name;
- 				return false;
- 			}
- 		} else if (strcmp(name, SIMPLE_ENCODER_AMD_AV1) == 0) {
- 			if (!amd_av1_supported) {
- 				changed = true;
--				name = SIMPLE_ENCODER_X264;
-+				name = fallback_encoder_name;
- 				return false;
- 			}
- 		} else if (strcmp(name, SIMPLE_ENCODER_APPLE_H264) == 0) {
- 			if (!apple_supported) {
- 				changed = true;
--				name = SIMPLE_ENCODER_X264;
-+				name = fallback_encoder_name;
- 				return false;
- 			}
- #ifdef ENABLE_HEVC
- 		} else if (strcmp(name, SIMPLE_ENCODER_APPLE_HEVC) == 0) {
- 			if (!apple_hevc_supported) {
- 				changed = true;
--				name = SIMPLE_ENCODER_X264;
-+				name = fallback_encoder_name;
- 				return false;
- 			}
- #endif
-diff --git a/UI/window-basic-main.cpp b/UI/window-basic-main.cpp
-index 6d9375eb4..c6aae8c7b 100644
---- a/UI/window-basic-main.cpp
-+++ b/UI/window-basic-main.cpp
-@@ -1379,6 +1379,8 @@ extern void CheckExistingCookieId();
- #define DEFAULT_CONTAINER "fragmented_mp4"
- #endif
- 
-+extern bool EncoderAvailable(const char *encoder);
-+
- bool OBSBasic::InitBasicConfigDefaults()
- {
- 	QList<QScreen *> screens = QGuiApplication::screens();
-@@ -1549,7 +1551,10 @@ bool OBSBasic::InitBasicConfigDefaults()
- 	config_set_default_bool(basicConfig, "AdvOut", "UseRescale", false);
- 	config_set_default_uint(basicConfig, "AdvOut", "TrackIndex", 1);
- 	config_set_default_uint(basicConfig, "AdvOut", "VodTrackIndex", 2);
--	config_set_default_string(basicConfig, "AdvOut", "Encoder", "obs_x264");
-+
-+	bool useX264 = EncoderAvailable("obs_x264");
-+	config_set_default_string(basicConfig, "AdvOut", "Encoder",
-+				  (useX264 ? "obs_x264" : "ffmpeg_openh264"));
- 
- 	config_set_default_string(basicConfig, "AdvOut", "RecType", "Standard");
- 
-@@ -1672,7 +1677,6 @@ bool OBSBasic::InitBasicConfigDefaults()
- 	return true;
- }
- 
--extern bool EncoderAvailable(const char *encoder);
- extern bool update_nvenc_presets(ConfigFile &config);
- 
- void OBSBasic::InitBasicConfigDefaults2()
-@@ -1681,12 +1685,14 @@ void OBSBasic::InitBasicConfigDefaults2()
- 					      "Pre23Defaults");
- 	bool useNV = EncoderAvailable("ffmpeg_nvenc") && !oldEncDefaults;
- 
-+	bool useX264 = EncoderAvailable("obs_x264");
-+	const char *h264_fallback =
-+		(useX264 ? SIMPLE_ENCODER_X264 : SIMPLE_ENCODER_OPENH264);
-+
- 	config_set_default_string(basicConfig, "SimpleOutput", "StreamEncoder",
--				  useNV ? SIMPLE_ENCODER_NVENC
--					: SIMPLE_ENCODER_X264);
-+				  useNV ? SIMPLE_ENCODER_NVENC : h264_fallback);
- 	config_set_default_string(basicConfig, "SimpleOutput", "RecEncoder",
--				  useNV ? SIMPLE_ENCODER_NVENC
--					: SIMPLE_ENCODER_X264);
-+				  useNV ? SIMPLE_ENCODER_NVENC : h264_fallback);
- 
- 	const char *aac_default = "ffmpeg_aac";
- 	if (EncoderAvailable("CoreAudio_AAC"))
-@@ -1967,7 +1973,7 @@ void OBSBasic::OBSInit()
- 
- 	InitBasicConfigDefaults2();
- 
--	CheckForSimpleModeX264Fallback();
-+	CheckForSimpleModeH264Fallback();
- 
- 	blog(LOG_INFO, STARTUP_SEPARATOR);
- 
-diff --git a/UI/window-basic-main.hpp b/UI/window-basic-main.hpp
-index cbce69832..74c6eb144 100644
---- a/UI/window-basic-main.hpp
-+++ b/UI/window-basic-main.hpp
-@@ -66,6 +66,7 @@ class OBSBasicVCamConfig;
- 
- #define SIMPLE_ENCODER_X264 "x264"
- #define SIMPLE_ENCODER_X264_LOWCPU "x264_lowcpu"
-+#define SIMPLE_ENCODER_OPENH264 "ffmpeg_openh264"
- #define SIMPLE_ENCODER_QSV "qsv"
- #define SIMPLE_ENCODER_QSV_AV1 "qsv_av1"
- #define SIMPLE_ENCODER_NVENC "nvenc"
-@@ -434,7 +435,7 @@ private:
- 	void DeleteProfile(const char *profile_name, const char *profile_dir);
- 	void RefreshProfiles();
- 	void ChangeProfile();
--	void CheckForSimpleModeX264Fallback();
-+	void CheckForSimpleModeH264Fallback();
- 
- 	void SaveProjectNow();
- 
-diff --git a/UI/window-basic-settings-stream.cpp b/UI/window-basic-settings-stream.cpp
-index b056938e7..548e5f45f 100644
---- a/UI/window-basic-settings-stream.cpp
-+++ b/UI/window-basic-settings-stream.cpp
-@@ -1362,7 +1362,9 @@ static QString get_adv_fallback(const QString &enc)
- 		return "com.apple.videotoolbox.videoencoder.ave.avc";
- 	if (enc == "obs_qsv11_av1")
- 		return "obs_qsv11";
--	return "obs_x264";
-+	if (EncoderAvailable("obs_x264"))
-+		return "obs_x264";
-+	return "ffmpeg_openh264";
- }
- 
- static QString get_adv_audio_fallback(const QString &enc)
-@@ -1391,7 +1393,9 @@ static QString get_simple_fallback(const QString &enc)
- 		return SIMPLE_ENCODER_APPLE_H264;
- 	if (enc == SIMPLE_ENCODER_QSV_AV1)
- 		return SIMPLE_ENCODER_QSV;
--	return SIMPLE_ENCODER_X264;
-+	if (EncoderAvailable("obs_x264"))
-+		return SIMPLE_ENCODER_X264;
-+	return SIMPLE_ENCODER_OPENH264;
- }
- 
- bool OBSBasicSettings::ServiceSupportsCodecCheck()
-@@ -1585,8 +1589,12 @@ void OBSBasicSettings::ResetEncoders(bool streamOnly)
- 
- #define ENCODER_STR(str) QTStr("Basic.Settings.Output.Simple.Encoder." str)
- 
--	ui->simpleOutStrEncoder->addItem(ENCODER_STR("Software.X264.H264"),
--					 QString(SIMPLE_ENCODER_X264));
-+	ui->simpleOutStrEncoder->addItem(ENCODER_STR("Software.OpenH264.H264"),
-+					 QString(SIMPLE_ENCODER_OPENH264));
-+	if (service_supports_encoder(vcodecs, "obs_x264"))
-+		ui->simpleOutStrEncoder->addItem(
-+			ENCODER_STR("Software.X264.H264"),
-+			QString(SIMPLE_ENCODER_X264));
- 	if (service_supports_encoder(vcodecs, "obs_qsv11"))
- 		ui->simpleOutStrEncoder->addItem(
- 			ENCODER_STR("Hardware.QSV.H264"),
-diff --git a/UI/window-basic-settings.cpp b/UI/window-basic-settings.cpp
-index 48bb4bac6..51fe280db 100644
---- a/UI/window-basic-settings.cpp
-+++ b/UI/window-basic-settings.cpp
-@@ -3831,6 +3831,11 @@ void OBSBasicSettings::SaveOutputSettings()
-          do. This only exists to make sure that the x264 preset doesn't
-          get overwritten with empty data. */
- 		presetType = "ApplePreset";
-+	else if (encoder == SIMPLE_ENCODER_OPENH264)
-+		/* The OpenH264 encoder does not have presets like the other encoders
-+         do. This only exists to make sure that the x264 preset doesn't
-+         get overwritten with empty data. */
-+		presetType = "OpenH264Preset";
- 	else
- 		presetType = "Preset";
- 
-@@ -5286,11 +5291,16 @@ void OBSBasicSettings::FillSimpleRecordingValues()
- 	ADD_QUALITY("HQ");
- 	ADD_QUALITY("Lossless");
- 
--	ui->simpleOutRecEncoder->addItem(ENCODER_STR("Software.X264.H264"),
--					 QString(SIMPLE_ENCODER_X264));
--	ui->simpleOutRecEncoder->addItem(
--		ENCODER_STR("SoftwareLowCPU.X264.H264"),
--		QString(SIMPLE_ENCODER_X264_LOWCPU));
-+	ui->simpleOutRecEncoder->addItem(ENCODER_STR("Software.OpenH264.H264"),
-+					 QString(SIMPLE_ENCODER_OPENH264));
-+	if (EncoderAvailable("obs_x264")) {
-+		ui->simpleOutRecEncoder->addItem(
-+			ENCODER_STR("Software.X264.H264"),
-+			QString(SIMPLE_ENCODER_X264));
-+		ui->simpleOutRecEncoder->addItem(
-+			ENCODER_STR("SoftwareLowCPU.X264.H264"),
-+			QString(SIMPLE_ENCODER_X264_LOWCPU));
-+	}
- 	if (EncoderAvailable("obs_qsv11"))
- 		ui->simpleOutRecEncoder->addItem(
- 			ENCODER_STR("Hardware.QSV.H264"),
-@@ -5463,6 +5473,9 @@ void OBSBasicSettings::SimpleStreamingEncoderChanged()
- 
- 		defaultPreset = "balanced";
- 		preset = curAMDAV1Preset;
-+	} else if (encoder == SIMPLE_ENCODER_OPENH264) {
-+		ui->simpleOutPreset->setVisible(false);
-+		ui->simpleOutPresetLabel->setVisible(false);
- 	} else {
- 
- #define PRESET_STR(val) \
--- 
-2.39.2
-

diff --git a/0101-UI-Consistently-reference-the-software-H264-encoder-.patch b/0101-UI-Consistently-reference-the-software-H264-encoder-.patch
new file mode 100644
index 0000000..2d5992e
--- /dev/null
+++ b/0101-UI-Consistently-reference-the-software-H264-encoder-.patch
@@ -0,0 +1,104 @@
+From dfa857eceb0deaf1a273fbd3423364fd7268ea90 Mon Sep 17 00:00:00 2001
+From: Neal Gompa <neal@gompa.dev>
+Date: Sat, 7 Jan 2023 23:15:13 -0500
+Subject: [PATCH 101/103] UI: Consistently reference the software H264 encoder
+ properly
+
+The code here assumes that the only software encoder is the x264-based
+H.264 encoder. That may not always remain true. This change adjusts
+the encoder string to indicate that it's an H.264 encoder from x264.
+---
+ UI/data/locale/en-US.ini             | 4 ++--
+ UI/window-basic-auto-config-test.cpp | 6 +++---
+ UI/window-basic-settings-stream.cpp  | 2 +-
+ UI/window-basic-settings.cpp         | 7 ++++---
+ 4 files changed, 10 insertions(+), 9 deletions(-)
+
+diff --git a/UI/data/locale/en-US.ini b/UI/data/locale/en-US.ini
+index e62f38a26..339ac4d86 100644
+--- a/UI/data/locale/en-US.ini
++++ b/UI/data/locale/en-US.ini
+@@ -996,7 +996,7 @@ Basic.Settings.Output.Simple.Warn.Encoder="Warning: Recording with a software en
+ Basic.Settings.Output.Simple.Warn.Lossless="Warning: Lossless quality generates tremendously large file sizes! Lossless quality can use upward of 7 gigabytes of disk space per minute at high resolutions and framerates. Lossless is not recommended for long recordings unless you have a very large amount of disk space available."
+ 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.Software.X264.H264="Software (x264)"
+ Basic.Settings.Output.Simple.Encoder.Hardware.QSV.H264="Hardware (QSV, H.264)"
+ Basic.Settings.Output.Simple.Encoder.Hardware.QSV.AV1="Hardware (QSV, AV1)"
+ Basic.Settings.Output.Simple.Encoder.Hardware.AMD.H264="Hardware (AMD, H.264)"
+@@ -1007,7 +1007,7 @@ Basic.Settings.Output.Simple.Encoder.Hardware.NVENC.AV1="Hardware (NVENC, AV1)"
+ Basic.Settings.Output.Simple.Encoder.Hardware.NVENC.HEVC="Hardware (NVENC, HEVC)"
+ Basic.Settings.Output.Simple.Encoder.Hardware.Apple.H264="Hardware (Apple, H.264)"
+ Basic.Settings.Output.Simple.Encoder.Hardware.Apple.HEVC="Hardware (Apple, HEVC)"
+-Basic.Settings.Output.Simple.Encoder.SoftwareLowCPU="Software (x264 low CPU usage preset, increases file size)"
++Basic.Settings.Output.Simple.Encoder.SoftwareLowCPU.X264.H264="Software (x264 low CPU usage preset, increases file size)"
+ Basic.Settings.Output.Simple.Codec.AAC="AAC"
+ Basic.Settings.Output.Simple.Codec.AAC.Default="AAC (Default)"
+ Basic.Settings.Output.Simple.Codec.Opus="Opus"
+diff --git a/UI/window-basic-auto-config-test.cpp b/UI/window-basic-auto-config-test.cpp
+index 7d7c4278e..a8b5d884a 100644
+--- a/UI/window-basic-auto-config-test.cpp
++++ b/UI/window-basic-auto-config-test.cpp
+@@ -1010,7 +1010,7 @@ void AutoConfigTestPage::TestRecordingEncoderThread()
+ }
+ 
+ #define ENCODER_TEXT(x) "Basic.Settings.Output.Simple.Encoder." x
+-#define ENCODER_SOFTWARE ENCODER_TEXT("Software")
++#define ENCODER_X264 ENCODER_TEXT("Software.X264.H264")
+ #define ENCODER_NVENC ENCODER_TEXT("Hardware.NVENC.H264")
+ #define ENCODER_QSV ENCODER_TEXT("Hardware.QSV.H264")
+ #define ENCODER_AMD ENCODER_TEXT("Hardware.AMD.H264")
+@@ -1050,7 +1050,7 @@ void AutoConfigTestPage::FinalizeResults()
+ 	auto encName = [](AutoConfig::Encoder enc) -> QString {
+ 		switch (enc) {
+ 		case AutoConfig::Encoder::x264:
+-			return QTStr(ENCODER_SOFTWARE);
++			return QTStr(ENCODER_X264);
+ 		case AutoConfig::Encoder::NVENC:
+ 			return QTStr(ENCODER_NVENC);
+ 		case AutoConfig::Encoder::QSV:
+@@ -1063,7 +1063,7 @@ void AutoConfigTestPage::FinalizeResults()
+ 			return QTStr(QUALITY_SAME);
+ 		}
+ 
+-		return QTStr(ENCODER_SOFTWARE);
++		return QTStr(ENCODER_X264);
+ 	};
+ 
+ 	auto newLabel = [this](const char *str) -> QLabel * {
+diff --git a/UI/window-basic-settings-stream.cpp b/UI/window-basic-settings-stream.cpp
+index 2ad275a44..e2ba4b677 100644
+--- a/UI/window-basic-settings-stream.cpp
++++ b/UI/window-basic-settings-stream.cpp
+@@ -1670,7 +1670,7 @@ void OBSBasicSettings::ResetEncoders(bool streamOnly)
+ 
+ #define ENCODER_STR(str) QTStr("Basic.Settings.Output.Simple.Encoder." str)
+ 
+-	ui->simpleOutStrEncoder->addItem(ENCODER_STR("Software"),
++	ui->simpleOutStrEncoder->addItem(ENCODER_STR("Software.X264.H264"),
+ 					 QString(SIMPLE_ENCODER_X264));
+ #ifdef _WIN32
+ 	if (service_supports_encoder(vcodecs, "obs_qsv11"))
+diff --git a/UI/window-basic-settings.cpp b/UI/window-basic-settings.cpp
+index b1e6bd6fb..ddf0adc56 100644
+--- a/UI/window-basic-settings.cpp
++++ b/UI/window-basic-settings.cpp
+@@ -5237,10 +5237,11 @@ void OBSBasicSettings::FillSimpleRecordingValues()
+ 	ADD_QUALITY("HQ");
+ 	ADD_QUALITY("Lossless");
+ 
+-	ui->simpleOutRecEncoder->addItem(ENCODER_STR("Software"),
++	ui->simpleOutRecEncoder->addItem(ENCODER_STR("Software.X264.H264"),
+ 					 QString(SIMPLE_ENCODER_X264));
+-	ui->simpleOutRecEncoder->addItem(ENCODER_STR("SoftwareLowCPU"),
+-					 QString(SIMPLE_ENCODER_X264_LOWCPU));
++	ui->simpleOutRecEncoder->addItem(
++		ENCODER_STR("SoftwareLowCPU.X264.H264"),
++		QString(SIMPLE_ENCODER_X264_LOWCPU));
+ 	if (EncoderAvailable("obs_qsv11"))
+ 		ui->simpleOutRecEncoder->addItem(
+ 			ENCODER_STR("Hardware.QSV.H264"),
+-- 
+2.41.0
+

diff --git a/0102-obs-ffmpeg-Add-initial-support-for-the-OpenH264-H.26.patch b/0102-obs-ffmpeg-Add-initial-support-for-the-OpenH264-H.26.patch
new file mode 100644
index 0000000..519c5ea
--- /dev/null
+++ b/0102-obs-ffmpeg-Add-initial-support-for-the-OpenH264-H.26.patch
@@ -0,0 +1,346 @@
+From 939db8edca8161f4518900e750551814c2c6088e Mon Sep 17 00:00:00 2001
+From: Neal Gompa <neal@gompa.dev>
+Date: Sun, 26 Mar 2023 06:06:31 -0400
+Subject: [PATCH 102/103] obs-ffmpeg: Add initial support for the OpenH264
+ H.264 software codec
+
+This allows users to leverage the OpenH264 codec from Cisco to encode
+H.264 video content. It is significantly reduced in capability from
+alternatives, but it does the job.
+
+This also provides a framework for adding support for other H.264
+software codecs provided through FFmpeg.
+---
+ plugins/obs-ffmpeg/CMakeLists.txt        |   1 +
+ plugins/obs-ffmpeg/cmake/legacy.cmake    |   1 +
+ plugins/obs-ffmpeg/data/locale/en-US.ini |   3 +
+ plugins/obs-ffmpeg/obs-ffmpeg-h264.c     | 260 +++++++++++++++++++++++
+ plugins/obs-ffmpeg/obs-ffmpeg.c          |   2 +
+ 5 files changed, 267 insertions(+)
+ create mode 100644 plugins/obs-ffmpeg/obs-ffmpeg-h264.c
+
+diff --git a/plugins/obs-ffmpeg/CMakeLists.txt b/plugins/obs-ffmpeg/CMakeLists.txt
+index 04530ef39..b77f6366f 100644
+--- a/plugins/obs-ffmpeg/CMakeLists.txt
++++ b/plugins/obs-ffmpeg/CMakeLists.txt
+@@ -36,6 +36,7 @@ target_sources(
+           obs-ffmpeg-av1.c
+           obs-ffmpeg-compat.h
+           obs-ffmpeg-formats.h
++          obs-ffmpeg-h264.c
+           obs-ffmpeg-hls-mux.c
+           obs-ffmpeg-mux.c
+           obs-ffmpeg-mux.h
+diff --git a/plugins/obs-ffmpeg/cmake/legacy.cmake b/plugins/obs-ffmpeg/cmake/legacy.cmake
+index 4cc75b341..d2e11965d 100644
+--- a/plugins/obs-ffmpeg/cmake/legacy.cmake
++++ b/plugins/obs-ffmpeg/cmake/legacy.cmake
+@@ -40,6 +40,7 @@ target_sources(
+           obs-ffmpeg-video-encoders.c
+           obs-ffmpeg-audio-encoders.c
+           obs-ffmpeg-av1.c
++          obs-ffmpeg-h264.c
+           obs-ffmpeg-nvenc.c
+           obs-ffmpeg-output.c
+           obs-ffmpeg-mux.c
+diff --git a/plugins/obs-ffmpeg/data/locale/en-US.ini b/plugins/obs-ffmpeg/data/locale/en-US.ini
+index 9652be160..e18e39f5a 100644
+--- a/plugins/obs-ffmpeg/data/locale/en-US.ini
++++ b/plugins/obs-ffmpeg/data/locale/en-US.ini
+@@ -120,4 +120,7 @@ NVENC.CheckDrivers="Try installing the latest <a href=\"https://obsproject.com/g
+ 
+ AV1.8bitUnsupportedHdr="OBS does not support 8-bit output of Rec. 2100."
+ 
++H264.UnsupportedVideoFormat="Only video formats using 8-bit color are supported."
++H264.UnsupportedColorSpace="Only the Rec. 709 color space is supported."
++
+ ReconnectDelayTime="Reconnect Delay"
+diff --git a/plugins/obs-ffmpeg/obs-ffmpeg-h264.c b/plugins/obs-ffmpeg/obs-ffmpeg-h264.c
+new file mode 100644
+index 000000000..179a61ccf
+--- /dev/null
++++ b/plugins/obs-ffmpeg/obs-ffmpeg-h264.c
+@@ -0,0 +1,260 @@
++/******************************************************************************
++    Copyright (C) 2023 by Neal Gompa <neal@gompa.dev>
++    Partly derived from obs-ffmpeg-av1.c by Hugh Bailey <obs.jim@gmail.com>
++
++    This program is free software: you can redistribute it and/or modify
++    it under the terms of the GNU General Public License as published by
++    the Free Software Foundation, either version 2 of the License, or
++    (at your option) any later version.
++
++    This program is distributed in the hope that it will be useful,
++    but WITHOUT ANY WARRANTY; without even the implied warranty of
++    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++    GNU General Public License for more details.
++
++    You should have received a copy of the GNU General Public License
++    along with this program.  If not, see <http://www.gnu.org/licenses/>.
++******************************************************************************/
++
++#include "obs-ffmpeg-video-encoders.h"
++
++#define do_log(level, format, ...)                   \
++	blog(level, "[H.264 encoder: '%s'] " format, \
++	     obs_encoder_get_name(enc->ffve.encoder), ##__VA_ARGS__)
++
++#define error(format, ...) do_log(LOG_ERROR, format, ##__VA_ARGS__)
++#define warn(format, ...) do_log(LOG_WARNING, format, ##__VA_ARGS__)
++#define info(format, ...) do_log(LOG_INFO, format, ##__VA_ARGS__)
++#define debug(format, ...) do_log(LOG_DEBUG, format, ##__VA_ARGS__)
++
++enum h264_encoder_type {
++	H264_ENCODER_TYPE_OH264,
++};
++
++struct h264_encoder {
++	struct ffmpeg_video_encoder ffve;
++	enum h264_encoder_type type;
++
++	DARRAY(uint8_t) header;
++};
++
++static const char *oh264_getname(void *unused)
++{
++	UNUSED_PARAMETER(unused);
++	return "OpenH264";
++}
++
++static void h264_video_info(void *data, struct video_scale_info *info)
++{
++	UNUSED_PARAMETER(data);
++
++	// OpenH264 only supports I420
++	info->format = VIDEO_FORMAT_I420;
++}
++
++static bool h264_update(struct h264_encoder *enc, obs_data_t *settings)
++{
++	const char *profile = obs_data_get_string(settings, "profile");
++	int bitrate = (int)obs_data_get_int(settings, "bitrate");
++	int keyint_sec = 0;              // This is not supported by OpenH264
++	const char *rc_mode = "quality"; // We only want to use quality mode
++	int allow_skip_frames = 1;       // This is required for quality mode
++
++	video_t *video = obs_encoder_video(enc->ffve.encoder);
++	const struct video_output_info *voi = video_output_get_info(video);
++	struct video_scale_info info;
++
++	info.format = voi->format;
++	info.colorspace = voi->colorspace;
++	info.range = voi->range;
++
++	enc->ffve.context->thread_count = 0;
++
++	h264_video_info(enc, &info);
++
++	av_opt_set(enc->ffve.context->priv_data, "rc_mode", rc_mode, 0);
++	av_opt_set(enc->ffve.context->priv_data, "profile", profile, 0);
++	av_opt_set_int(enc->ffve.context->priv_data, "allow_skip_frames",
++		       allow_skip_frames, 0);
++
++	const char *ffmpeg_opts = obs_data_get_string(settings, "ffmpeg_opts");
++	ffmpeg_video_encoder_update(&enc->ffve, bitrate, keyint_sec, voi, &info,
++				    ffmpeg_opts);
++	info("settings:\n"
++	     "\tencoder:      %s\n"
++	     "\trc_mode:      %s\n"
++	     "\tbitrate:      %d\n"
++	     "\tprofile:      %s\n"
++	     "\twidth:        %d\n"
++	     "\theight:       %d\n"
++	     "\tffmpeg opts:  %s\n",
++	     enc->ffve.enc_name, rc_mode, bitrate, profile,
++	     enc->ffve.context->width, enc->ffve.height, ffmpeg_opts);
++
++	enc->ffve.context->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
++	return ffmpeg_video_encoder_init_codec(&enc->ffve);
++}
++
++static void h264_destroy(void *data)
++{
++	struct h264_encoder *enc = data;
++
++	ffmpeg_video_encoder_free(&enc->ffve);
++	da_free(enc->header);
++	bfree(enc);
++}
++
++static void on_first_packet(void *data, AVPacket *pkt, struct darray *da)
++{
++	struct h264_encoder *enc = data;
++
++	da_copy_array(enc->header, enc->ffve.context->extradata,
++		      enc->ffve.context->extradata_size);
++
++	darray_copy_array(1, da, pkt->data, pkt->size);
++}
++
++static void *h264_create_internal(obs_data_t *settings, obs_encoder_t *encoder,
++				  const char *enc_lib, const char *enc_name)
++{
++	video_t *video = obs_encoder_video(encoder);
++	const struct video_output_info *voi = video_output_get_info(video);
++
++	switch (voi->format) {
++	// planar 4:2:0 formats
++	case VIDEO_FORMAT_I420: // three-plane
++	case VIDEO_FORMAT_NV12: // two-plane, luma and packed chroma
++	// packed 4:2:2 formats
++	case VIDEO_FORMAT_YVYU:
++	case VIDEO_FORMAT_YUY2: // YUYV
++	case VIDEO_FORMAT_UYVY:
++	// packed uncompressed formats
++	case VIDEO_FORMAT_RGBA:
++	case VIDEO_FORMAT_BGRA:
++	case VIDEO_FORMAT_BGRX:
++	case VIDEO_FORMAT_BGR3:
++	case VIDEO_FORMAT_Y800: // grayscale
++	// planar 4:4:4
++	case VIDEO_FORMAT_I444:
++	// planar 4:2:2
++	case VIDEO_FORMAT_I422:
++	// planar 4:2:0 with alpha
++	case VIDEO_FORMAT_I40A:
++	// planar 4:2:2 with alpha
++	case VIDEO_FORMAT_I42A:
++	// planar 4:4:4 with alpha
++	case VIDEO_FORMAT_YUVA:
++	// packed 4:4:4 with alpha
++	case VIDEO_FORMAT_AYUV:
++		break;
++	default:; // Make the compiler do the right thing
++		const char *const text =
++			obs_module_text("H264.UnsupportedVideoFormat");
++		obs_encoder_set_last_error(encoder, text);
++		blog(LOG_ERROR, "[H.264 encoder] %s", text);
++		return NULL;
++	}
++
++	switch (voi->colorspace) {
++	case VIDEO_CS_DEFAULT:
++	case VIDEO_CS_709:
++		break;
++	default:; // Make the compiler do the right thing
++		const char *const text =
++			obs_module_text("H264.UnsupportedColorSpace");
++		obs_encoder_set_last_error(encoder, text);
++		blog(LOG_ERROR, "[H.264 encoder] %s", text);
++		return NULL;
++	}
++
++	struct h264_encoder *enc = bzalloc(sizeof(*enc));
++
++	if (strcmp(enc_lib, "libopenh264") == 0)
++		enc->type = H264_ENCODER_TYPE_OH264;
++
++	if (!ffmpeg_video_encoder_init(&enc->ffve, enc, encoder, enc_lib, NULL,
++				       enc_name, NULL, on_first_packet))
++		goto fail;
++	if (!h264_update(enc, settings))
++		goto fail;
++
++	return enc;
++
++fail:
++	h264_destroy(enc);
++	return NULL;
++}
++
++static void *oh264_create(obs_data_t *settings, obs_encoder_t *encoder)
++{
++	return h264_create_internal(settings, encoder, "libopenh264",
++				    "OpenH264");
++}
++
++static bool h264_encode(void *data, struct encoder_frame *frame,
++			struct encoder_packet *packet, bool *received_packet)
++{
++	struct h264_encoder *enc = data;
++	return ffmpeg_video_encode(&enc->ffve, frame, packet, received_packet);
++}
++
++void h264_defaults(obs_data_t *settings)
++{
++	obs_data_set_default_int(settings, "bitrate", 2500);
++	obs_data_set_default_string(settings, "profile", "main");
++}
++
++obs_properties_t *h264_properties(enum h264_encoder_type type)
++{
++	UNUSED_PARAMETER(type); // Only one encoder right now...
++	obs_properties_t *props = obs_properties_create();
++	obs_property_t *p;
++
++	p = obs_properties_add_list(props, "profile",
++				    obs_module_text("Profile"),
++				    OBS_COMBO_TYPE_LIST,
++				    OBS_COMBO_FORMAT_STRING);
++	obs_property_list_add_string(p, "constrained_baseline",
++				     "constrained_baseline");
++	obs_property_list_add_string(p, "main", "main");
++	obs_property_list_add_string(p, "high", "high");
++
++	p = obs_properties_add_int(props, "bitrate", obs_module_text("Bitrate"),
++				   50, 300000, 50);
++	obs_property_int_set_suffix(p, " Kbps");
++
++	obs_properties_add_text(props, "ffmpeg_opts",
++				obs_module_text("FFmpegOpts"),
++				OBS_TEXT_DEFAULT);
++
++	return props;
++}
++
++obs_properties_t *oh264_properties(void *unused)
++{
++	UNUSED_PARAMETER(unused);
++	return h264_properties(H264_ENCODER_TYPE_OH264);
++}
++
++static bool h264_extra_data(void *data, uint8_t **extra_data, size_t *size)
++{
++	struct h264_encoder *enc = data;
++
++	*extra_data = enc->header.array;
++	*size = enc->header.num;
++	return true;
++}
++
++struct obs_encoder_info oh264_encoder_info = {
++	.id = "ffmpeg_openh264",
++	.type = OBS_ENCODER_VIDEO,
++	.codec = "h264",
++	.get_name = oh264_getname,
++	.create = oh264_create,
++	.destroy = h264_destroy,
++	.encode = h264_encode,
++	.get_defaults = h264_defaults,
++	.get_properties = oh264_properties,
++	.get_extra_data = h264_extra_data,
++	.get_video_info = h264_video_info,
++};
+diff --git a/plugins/obs-ffmpeg/obs-ffmpeg.c b/plugins/obs-ffmpeg/obs-ffmpeg.c
+index 7eb9a876d..fcce8ec3b 100644
+--- a/plugins/obs-ffmpeg/obs-ffmpeg.c
++++ b/plugins/obs-ffmpeg/obs-ffmpeg.c
+@@ -38,6 +38,7 @@ extern struct obs_encoder_info pcm24_encoder_info;
+ extern struct obs_encoder_info pcm32_encoder_info;
+ extern struct obs_encoder_info alac_encoder_info;
+ extern struct obs_encoder_info flac_encoder_info;
++extern struct obs_encoder_info oh264_encoder_info;
+ extern struct obs_encoder_info h264_nvenc_encoder_info;
+ #ifdef ENABLE_HEVC
+ extern struct obs_encoder_info hevc_nvenc_encoder_info;
+@@ -382,6 +383,7 @@ bool obs_module_load(void)
+ 	obs_register_output(&ffmpeg_hls_muxer);
+ 	obs_register_output(&replay_buffer);
+ 	obs_register_encoder(&aac_encoder_info);
++	register_encoder_if_available(&oh264_encoder_info, "libopenh264");
+ 	register_encoder_if_available(&svt_av1_encoder_info, "libsvtav1");
+ 	register_encoder_if_available(&aom_av1_encoder_info, "libaom-av1");
+ 	obs_register_encoder(&opus_encoder_info);
+-- 
+2.41.0
+

diff --git a/0103-UI-Add-support-for-OpenH264-as-the-worst-case-fallba.patch b/0103-UI-Add-support-for-OpenH264-as-the-worst-case-fallba.patch
new file mode 100644
index 0000000..c8a3074
--- /dev/null
+++ b/0103-UI-Add-support-for-OpenH264-as-the-worst-case-fallba.patch
@@ -0,0 +1,546 @@
+From f26c32b97117273550b9dddea01b5b92684c6886 Mon Sep 17 00:00:00 2001
+From: Neal Gompa <neal@gompa.dev>
+Date: Tue, 28 Mar 2023 05:08:49 -0400
+Subject: [PATCH 103/103] UI: Add support for OpenH264 as the worst-case
+ fallback
+
+OpenH264 exists as the codec of last resort, so it is implemented
+such that it is only used as the software codec if x264 is not
+available.
+---
+ UI/data/locale/en-US.ini             |  1 +
+ UI/window-basic-auto-config-test.cpp | 50 +++++++++++++++++++---------
+ UI/window-basic-auto-config.cpp      | 15 ++++++++-
+ UI/window-basic-auto-config.hpp      |  3 ++
+ UI/window-basic-main-outputs.cpp     |  6 ++--
+ UI/window-basic-main-profiles.cpp    | 34 +++++++++++--------
+ UI/window-basic-main.cpp             | 20 +++++++----
+ UI/window-basic-main.hpp             |  3 +-
+ UI/window-basic-settings-stream.cpp  | 16 ++++++---
+ UI/window-basic-settings.cpp         | 23 ++++++++++---
+ 10 files changed, 123 insertions(+), 48 deletions(-)
+
+diff --git a/UI/data/locale/en-US.ini b/UI/data/locale/en-US.ini
+index 339ac4d86..ff8c649da 100644
+--- a/UI/data/locale/en-US.ini
++++ b/UI/data/locale/en-US.ini
+@@ -996,6 +996,7 @@ Basic.Settings.Output.Simple.Warn.Encoder="Warning: Recording with a software en
+ Basic.Settings.Output.Simple.Warn.Lossless="Warning: Lossless quality generates tremendously large file sizes! Lossless quality can use upward of 7 gigabytes of disk space per minute at high resolutions and framerates. Lossless is not recommended for long recordings unless you have a very large amount of disk space available."
+ 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.OpenH264.H264="Software (OpenH264)"
+ Basic.Settings.Output.Simple.Encoder.Software.X264.H264="Software (x264)"
+ Basic.Settings.Output.Simple.Encoder.Hardware.QSV.H264="Hardware (QSV, H.264)"
+ Basic.Settings.Output.Simple.Encoder.Hardware.QSV.AV1="Hardware (QSV, AV1)"
+diff --git a/UI/window-basic-auto-config-test.cpp b/UI/window-basic-auto-config-test.cpp
+index a8b5d884a..e68a33bb5 100644
+--- a/UI/window-basic-auto-config-test.cpp
++++ b/UI/window-basic-auto-config-test.cpp
+@@ -199,7 +199,8 @@ void AutoConfigTestPage::TestBandwidthThread()
+ 						   : "rtmp_common";
+ 
+ 	OBSEncoderAutoRelease vencoder = obs_video_encoder_create(
+-		"obs_x264", "test_x264", nullptr, nullptr);
++		(wiz->x264Available ? "obs_x264" : "ffmpeg_openh264"),
++		"test_h264", nullptr, nullptr);
+ 	OBSEncoderAutoRelease aencoder = obs_audio_encoder_create(
+ 		"ffmpeg_aac", "test_aac", nullptr, 0, nullptr);
+ 	OBSServiceAutoRelease service = obs_service_create(
+@@ -238,10 +239,11 @@ void AutoConfigTestPage::TestBandwidthThread()
+ 	obs_data_set_string(service_settings, "key", key.c_str());
+ 
+ 	obs_data_set_int(vencoder_settings, "bitrate", wiz->startingBitrate);
+-	obs_data_set_string(vencoder_settings, "rate_control", "CBR");
+-	obs_data_set_string(vencoder_settings, "preset", "veryfast");
+-	obs_data_set_int(vencoder_settings, "keyint_sec", 2);
+-
++	if (wiz->x264Available) {
++		obs_data_set_string(vencoder_settings, "rate_control", "CBR");
++		obs_data_set_string(vencoder_settings, "preset", "veryfast");
++		obs_data_set_int(vencoder_settings, "keyint_sec", 2);
++	}
+ 	obs_data_set_int(aencoder_settings, "bitrate", 32);
+ 
+ 	OBSBasic *main = reinterpret_cast<OBSBasic *>(App()->GetMainWindow());
+@@ -574,7 +576,8 @@ bool AutoConfigTestPage::TestSoftwareEncoding()
+ 	/* create obs objects                 */
+ 
+ 	OBSEncoderAutoRelease vencoder = obs_video_encoder_create(
+-		"obs_x264", "test_x264", nullptr, nullptr);
++		(wiz->x264Available ? "obs_x264" : "ffmpeg_openh264"),
++		"test_h264", nullptr, nullptr);
+ 	OBSEncoderAutoRelease aencoder = obs_audio_encoder_create(
+ 		"ffmpeg_aac", "test_aac", nullptr, 0, nullptr);
+ 	OBSOutputAutoRelease output =
+@@ -588,17 +591,25 @@ bool AutoConfigTestPage::TestSoftwareEncoding()
+ 	obs_data_set_int(aencoder_settings, "bitrate", 32);
+ 
+ 	if (wiz->type != AutoConfig::Type::Recording) {
+-		obs_data_set_int(vencoder_settings, "keyint_sec", 2);
++		if (wiz->x264Available) {
++			obs_data_set_int(vencoder_settings, "keyint_sec", 2);
++			obs_data_set_string(vencoder_settings, "rate_control",
++					    "CBR");
++			obs_data_set_string(vencoder_settings, "preset",
++					    "veryfast");
++		}
+ 		obs_data_set_int(vencoder_settings, "bitrate",
+ 				 wiz->idealBitrate);
+-		obs_data_set_string(vencoder_settings, "rate_control", "CBR");
+ 		obs_data_set_string(vencoder_settings, "profile", "main");
+-		obs_data_set_string(vencoder_settings, "preset", "veryfast");
+ 	} else {
+-		obs_data_set_int(vencoder_settings, "crf", 20);
+-		obs_data_set_string(vencoder_settings, "rate_control", "CRF");
++		if (wiz->x264Available) {
++			obs_data_set_int(vencoder_settings, "crf", 20);
++			obs_data_set_string(vencoder_settings, "rate_control",
++					    "CRF");
++			obs_data_set_string(vencoder_settings, "preset",
++					    "veryfast");
++		}
+ 		obs_data_set_string(vencoder_settings, "profile", "high");
+-		obs_data_set_string(vencoder_settings, "preset", "veryfast");
+ 	}
+ 
+ 	/* -----------------------------------*/
+@@ -951,7 +962,10 @@ void AutoConfigTestPage::TestStreamEncoderThread()
+ 		else
+ 			wiz->streamingEncoder = AutoConfig::Encoder::AMD;
+ 	} else {
+-		wiz->streamingEncoder = AutoConfig::Encoder::x264;
++		if (wiz->x264Available)
++			wiz->streamingEncoder = AutoConfig::Encoder::x264;
++		else
++			wiz->streamingEncoder = AutoConfig::Encoder::OpenH264;
+ 	}
+ 
+ #ifdef __linux__
+@@ -996,7 +1010,10 @@ void AutoConfigTestPage::TestRecordingEncoderThread()
+ 		else
+ 			wiz->recordingEncoder = AutoConfig::Encoder::AMD;
+ 	} else {
+-		wiz->recordingEncoder = AutoConfig::Encoder::x264;
++		if (wiz->x264Available)
++			wiz->streamingEncoder = AutoConfig::Encoder::x264;
++		else
++			wiz->streamingEncoder = AutoConfig::Encoder::OpenH264;
+ 	}
+ 
+ 	if (wiz->recordingEncoder != AutoConfig::Encoder::NVENC) {
+@@ -1010,6 +1027,7 @@ void AutoConfigTestPage::TestRecordingEncoderThread()
+ }
+ 
+ #define ENCODER_TEXT(x) "Basic.Settings.Output.Simple.Encoder." x
++#define ENCODER_OPENH264 ENCODER_TEXT("Software.OpenH264.H264")
+ #define ENCODER_X264 ENCODER_TEXT("Software.X264.H264")
+ #define ENCODER_NVENC ENCODER_TEXT("Hardware.NVENC.H264")
+ #define ENCODER_QSV ENCODER_TEXT("Hardware.QSV.H264")
+@@ -1049,6 +1067,8 @@ void AutoConfigTestPage::FinalizeResults()
+ 
+ 	auto encName = [](AutoConfig::Encoder enc) -> QString {
+ 		switch (enc) {
++		case AutoConfig::Encoder::OpenH264:
++			return QTStr(ENCODER_OPENH264);
+ 		case AutoConfig::Encoder::x264:
+ 			return QTStr(ENCODER_X264);
+ 		case AutoConfig::Encoder::NVENC:
+@@ -1063,7 +1083,7 @@ void AutoConfigTestPage::FinalizeResults()
+ 			return QTStr(QUALITY_SAME);
+ 		}
+ 
+-		return QTStr(ENCODER_X264);
++		return QTStr(ENCODER_OPENH264);
+ 	};
+ 
+ 	auto newLabel = [this](const char *str) -> QLabel * {
+diff --git a/UI/window-basic-auto-config.cpp b/UI/window-basic-auto-config.cpp
+index d8ddbfa44..4707a5644 100644
+--- a/UI/window-basic-auto-config.cpp
++++ b/UI/window-basic-auto-config.cpp
+@@ -979,6 +979,7 @@ AutoConfig::AutoConfig(QWidget *parent) : QWizard(parent)
+ 	streamPage->ui->bitrate->setValue(bitrate);
+ 	streamPage->ServiceChanged();
+ 
++	TestSoftwareEncoding();
+ 	TestHardwareEncoding();
+ 	if (!hardwareEncodingAvailable) {
+ 		delete streamPage->ui->preferHardware;
+@@ -1007,6 +1008,16 @@ AutoConfig::~AutoConfig()
+ 	EnableThreadedMessageBoxes(false);
+ }
+ 
++void AutoConfig::TestSoftwareEncoding()
++{
++	size_t idx = 0;
++	const char *id;
++	while (obs_enum_encoder_types(idx++, &id)) {
++		if (strcmp(id, "obs_x264") == 0)
++			x264Available = true;
++	}
++}
++
+ void AutoConfig::TestHardwareEncoding()
+ {
+ 	size_t idx = 0;
+@@ -1086,8 +1097,10 @@ inline const char *AutoConfig::GetEncoderId(Encoder enc)
+ 		return SIMPLE_ENCODER_AMD;
+ 	case Encoder::Apple:
+ 		return SIMPLE_ENCODER_APPLE_H264;
+-	default:
++	case Encoder::x264:
+ 		return SIMPLE_ENCODER_X264;
++	default:
++		return SIMPLE_ENCODER_OPENH264;
+ 	}
+ };
+ 
+diff --git a/UI/window-basic-auto-config.hpp b/UI/window-basic-auto-config.hpp
+index 5d966c795..c17e32a85 100644
+--- a/UI/window-basic-auto-config.hpp
++++ b/UI/window-basic-auto-config.hpp
+@@ -43,6 +43,7 @@ class AutoConfig : public QWizard {
+ 	};
+ 
+ 	enum class Encoder {
++		OpenH264,
+ 		x264,
+ 		NVENC,
+ 		QSV,
+@@ -91,6 +92,7 @@ class AutoConfig : public QWizard {
+ 	bool qsvAvailable = false;
+ 	bool vceAvailable = false;
+ 	bool appleAvailable = false;
++	bool x264Available = false;
+ 
+ 	int startingBitrate = 2500;
+ 	bool customServer = false;
+@@ -106,6 +108,7 @@ class AutoConfig : public QWizard {
+ 	int specificFPSNum = 0;
+ 	int specificFPSDen = 0;
+ 
++	void TestSoftwareEncoding();
+ 	void TestHardwareEncoding();
+ 	bool CanTestServer(const char *server);
+ 
+diff --git a/UI/window-basic-main-outputs.cpp b/UI/window-basic-main-outputs.cpp
+index a283d0fcc..4b3f25371 100644
+--- a/UI/window-basic-main-outputs.cpp
++++ b/UI/window-basic-main-outputs.cpp
+@@ -547,7 +547,9 @@ void SimpleOutput::LoadStreamingPreset_Lossy(const char *encoderId)
+ /* mistakes have been made to lead us to this. */
+ const char *get_simple_output_encoder(const char *encoder)
+ {
+-	if (strcmp(encoder, SIMPLE_ENCODER_X264) == 0) {
++	if (strcmp(encoder, SIMPLE_ENCODER_OPENH264) == 0) {
++		return "ffmpeg_openh264";
++	} else if (strcmp(encoder, SIMPLE_ENCODER_X264) == 0) {
+ 		return "obs_x264";
+ 	} else if (strcmp(encoder, SIMPLE_ENCODER_X264_LOWCPU) == 0) {
+ 		return "obs_x264";
+@@ -581,7 +583,7 @@ const char *get_simple_output_encoder(const char *encoder)
+ #endif
+ 	}
+ 
+-	return "obs_x264";
++	return "ffmpeg_openh264";
+ }
+ 
+ void SimpleOutput::LoadRecordingPreset()
+diff --git a/UI/window-basic-main-profiles.cpp b/UI/window-basic-main-profiles.cpp
+index f9d3f4ea1..27899efc4 100644
+--- a/UI/window-basic-main-profiles.cpp
++++ b/UI/window-basic-main-profiles.cpp
+@@ -806,7 +806,7 @@ void OBSBasic::ChangeProfile()
+ 		NewYouTubeAppDock();
+ #endif
+ 
+-	CheckForSimpleModeX264Fallback();
++	CheckForSimpleModeH264Fallback();
+ 
+ 	blog(LOG_INFO, "Switched to profile '%s' (%s)", newName, newDir);
+ 	blog(LOG_INFO, "------------------------------------------------");
+@@ -827,12 +827,13 @@ void OBSBasic::ChangeProfile()
+ 	}
+ }
+ 
+-void OBSBasic::CheckForSimpleModeX264Fallback()
++void OBSBasic::CheckForSimpleModeH264Fallback()
+ {
+ 	const char *curStreamEncoder =
+ 		config_get_string(basicConfig, "SimpleOutput", "StreamEncoder");
+ 	const char *curRecEncoder =
+ 		config_get_string(basicConfig, "SimpleOutput", "RecEncoder");
++	bool x264_supported = false;
+ 	bool qsv_supported = false;
+ 	bool qsv_av1_supported = false;
+ 	bool amd_supported = false;
+@@ -849,7 +850,9 @@ void OBSBasic::CheckForSimpleModeX264Fallback()
+ 	const char *id;
+ 
+ 	while (obs_enum_encoder_types(idx++, &id)) {
+-		if (strcmp(id, "h264_texture_amf") == 0)
++		if (strcmp(id, "obs_x264") == 0)
++			x264_supported = true;
++		else if (strcmp(id, "h264_texture_amf") == 0)
+ 			amd_supported = true;
+ 		else if (strcmp(id, "obs_qsv11") == 0)
+ 			qsv_supported = true;
+@@ -877,68 +880,73 @@ void OBSBasic::CheckForSimpleModeX264Fallback()
+ #endif
+ 	}
+ 
++	// Check to see whether x264 is available
++	const char *fallback_encoder_name = (x264_supported
++						     ? SIMPLE_ENCODER_X264
++						     : SIMPLE_ENCODER_OPENH264);
++
+ 	auto CheckEncoder = [&](const char *&name) {
+ 		if (strcmp(name, SIMPLE_ENCODER_QSV) == 0) {
+ 			if (!qsv_supported) {
+ 				changed = true;
+-				name = SIMPLE_ENCODER_X264;
++				name = fallback_encoder_name;
+ 				return false;
+ 			}
+ 		} else if (strcmp(name, SIMPLE_ENCODER_QSV_AV1) == 0) {
+ 			if (!qsv_av1_supported) {
+ 				changed = true;
+-				name = SIMPLE_ENCODER_X264;
++				name = fallback_encoder_name;
+ 				return false;
+ 			}
+ 		} else if (strcmp(name, SIMPLE_ENCODER_NVENC) == 0) {
+ 			if (!nve_supported) {
+ 				changed = true;
+-				name = SIMPLE_ENCODER_X264;
++				name = fallback_encoder_name;
+ 				return false;
+ 			}
+ 		} else if (strcmp(name, SIMPLE_ENCODER_NVENC_AV1) == 0) {
+ 			if (!nve_supported) {
+ 				changed = true;
+-				name = SIMPLE_ENCODER_X264;
++				name = fallback_encoder_name;
+ 				return false;
+ 			}
+ #ifdef ENABLE_HEVC
+ 		} else if (strcmp(name, SIMPLE_ENCODER_AMD_HEVC) == 0) {
+ 			if (!amd_hevc_supported) {
+ 				changed = true;
+-				name = SIMPLE_ENCODER_X264;
++				name = fallback_encoder_name;
+ 				return false;
+ 			}
+ 		} else if (strcmp(name, SIMPLE_ENCODER_NVENC_HEVC) == 0) {
+ 			if (!nve_hevc_supported) {
+ 				changed = true;
+-				name = SIMPLE_ENCODER_X264;
++				name = fallback_encoder_name;
+ 				return false;
+ 			}
+ #endif
+ 		} else if (strcmp(name, SIMPLE_ENCODER_AMD) == 0) {
+ 			if (!amd_supported) {
+ 				changed = true;
+-				name = SIMPLE_ENCODER_X264;
++				name = fallback_encoder_name;
+ 				return false;
+ 			}
+ 		} else if (strcmp(name, SIMPLE_ENCODER_AMD_AV1) == 0) {
+ 			if (!amd_av1_supported) {
+ 				changed = true;
+-				name = SIMPLE_ENCODER_X264;
++				name = fallback_encoder_name;
+ 				return false;
+ 			}
+ 		} else if (strcmp(name, SIMPLE_ENCODER_APPLE_H264) == 0) {
+ 			if (!apple_supported) {
+ 				changed = true;
+-				name = SIMPLE_ENCODER_X264;
++				name = fallback_encoder_name;
+ 				return false;
+ 			}
+ #ifdef ENABLE_HEVC
+ 		} else if (strcmp(name, SIMPLE_ENCODER_APPLE_HEVC) == 0) {
+ 			if (!apple_hevc_supported) {
+ 				changed = true;
+-				name = SIMPLE_ENCODER_X264;
++				name = fallback_encoder_name;
+ 				return false;
+ 			}
+ #endif
+diff --git a/UI/window-basic-main.cpp b/UI/window-basic-main.cpp
+index 943e8cac1..09251de75 100644
+--- a/UI/window-basic-main.cpp
++++ b/UI/window-basic-main.cpp
+@@ -1449,6 +1449,8 @@ extern void CheckExistingCookieId();
+ #define DEFAULT_CONTAINER "fragmented_mp4"
+ #endif
+ 
++extern bool EncoderAvailable(const char *encoder);
++
+ bool OBSBasic::InitBasicConfigDefaults()
+ {
+ 	QList<QScreen *> screens = QGuiApplication::screens();
+@@ -1619,7 +1621,10 @@ bool OBSBasic::InitBasicConfigDefaults()
+ 	config_set_default_bool(basicConfig, "AdvOut", "UseRescale", false);
+ 	config_set_default_uint(basicConfig, "AdvOut", "TrackIndex", 1);
+ 	config_set_default_uint(basicConfig, "AdvOut", "VodTrackIndex", 2);
+-	config_set_default_string(basicConfig, "AdvOut", "Encoder", "obs_x264");
++
++	bool useX264 = EncoderAvailable("obs_x264");
++	config_set_default_string(basicConfig, "AdvOut", "Encoder",
++				  (useX264 ? "obs_x264" : "ffmpeg_openh264"));
+ 
+ 	config_set_default_string(basicConfig, "AdvOut", "RecType", "Standard");
+ 
+@@ -1744,7 +1749,6 @@ bool OBSBasic::InitBasicConfigDefaults()
+ 	return true;
+ }
+ 
+-extern bool EncoderAvailable(const char *encoder);
+ extern bool update_nvenc_presets(ConfigFile &config);
+ 
+ void OBSBasic::InitBasicConfigDefaults2()
+@@ -1753,12 +1757,14 @@ void OBSBasic::InitBasicConfigDefaults2()
+ 					      "Pre23Defaults");
+ 	bool useNV = EncoderAvailable("ffmpeg_nvenc") && !oldEncDefaults;
+ 
++	bool useX264 = EncoderAvailable("obs_x264");
++	const char *h264_fallback =
++		(useX264 ? SIMPLE_ENCODER_X264 : SIMPLE_ENCODER_OPENH264);
++
+ 	config_set_default_string(basicConfig, "SimpleOutput", "StreamEncoder",
+-				  useNV ? SIMPLE_ENCODER_NVENC
+-					: SIMPLE_ENCODER_X264);
++				  useNV ? SIMPLE_ENCODER_NVENC : h264_fallback);
+ 	config_set_default_string(basicConfig, "SimpleOutput", "RecEncoder",
+-				  useNV ? SIMPLE_ENCODER_NVENC
+-					: SIMPLE_ENCODER_X264);
++				  useNV ? SIMPLE_ENCODER_NVENC : h264_fallback);
+ 
+ 	const char *aac_default = "ffmpeg_aac";
+ 	if (EncoderAvailable("CoreAudio_AAC"))
+@@ -2040,7 +2046,7 @@ void OBSBasic::OBSInit()
+ 
+ 	InitBasicConfigDefaults2();
+ 
+-	CheckForSimpleModeX264Fallback();
++	CheckForSimpleModeH264Fallback();
+ 
+ 	blog(LOG_INFO, STARTUP_SEPARATOR);
+ 
+diff --git a/UI/window-basic-main.hpp b/UI/window-basic-main.hpp
+index b1eb39592..7d9e8d286 100644
+--- a/UI/window-basic-main.hpp
++++ b/UI/window-basic-main.hpp
+@@ -69,6 +69,7 @@ class OBSBasicVCamConfig;
+ 
+ #define SIMPLE_ENCODER_X264 "x264"
+ #define SIMPLE_ENCODER_X264_LOWCPU "x264_lowcpu"
++#define SIMPLE_ENCODER_OPENH264 "ffmpeg_openh264"
+ #define SIMPLE_ENCODER_QSV "qsv"
+ #define SIMPLE_ENCODER_QSV_AV1 "qsv_av1"
+ #define SIMPLE_ENCODER_NVENC "nvenc"
+@@ -446,7 +447,7 @@ private:
+ 	void DeleteProfile(const char *profile_name, const char *profile_dir);
+ 	void RefreshProfiles();
+ 	void ChangeProfile();
+-	void CheckForSimpleModeX264Fallback();
++	void CheckForSimpleModeH264Fallback();
+ 
+ 	void SaveProjectNow();
+ 
+diff --git a/UI/window-basic-settings-stream.cpp b/UI/window-basic-settings-stream.cpp
+index e2ba4b677..a08c697d4 100644
+--- a/UI/window-basic-settings-stream.cpp
++++ b/UI/window-basic-settings-stream.cpp
+@@ -1437,7 +1437,9 @@ static QString get_adv_fallback(const QString &enc)
+ 		return "com.apple.videotoolbox.videoencoder.ave.avc";
+ 	if (enc == "obs_qsv11_av1")
+ 		return "obs_qsv11";
+-	return "obs_x264";
++	if (EncoderAvailable("obs_x264"))
++		return "obs_x264";
++	return "ffmpeg_openh264";
+ }
+ 
+ static QString get_adv_audio_fallback(const QString &enc)
+@@ -1466,7 +1468,9 @@ static QString get_simple_fallback(const QString &enc)
+ 		return SIMPLE_ENCODER_APPLE_H264;
+ 	if (enc == SIMPLE_ENCODER_QSV_AV1)
+ 		return SIMPLE_ENCODER_QSV;
+-	return SIMPLE_ENCODER_X264;
++	if (EncoderAvailable("obs_x264"))
++		return SIMPLE_ENCODER_X264;
++	return SIMPLE_ENCODER_OPENH264;
+ }
+ 
+ bool OBSBasicSettings::ServiceSupportsCodecCheck()
+@@ -1670,8 +1674,12 @@ void OBSBasicSettings::ResetEncoders(bool streamOnly)
+ 
+ #define ENCODER_STR(str) QTStr("Basic.Settings.Output.Simple.Encoder." str)
+ 
+-	ui->simpleOutStrEncoder->addItem(ENCODER_STR("Software.X264.H264"),
+-					 QString(SIMPLE_ENCODER_X264));
++	ui->simpleOutStrEncoder->addItem(ENCODER_STR("Software.OpenH264.H264"),
++					 QString(SIMPLE_ENCODER_OPENH264));
++	if (service_supports_encoder(vcodecs, "obs_x264"))
++		ui->simpleOutStrEncoder->addItem(
++			ENCODER_STR("Software.X264.H264"),
++			QString(SIMPLE_ENCODER_X264));
+ #ifdef _WIN32
+ 	if (service_supports_encoder(vcodecs, "obs_qsv11"))
+ 		ui->simpleOutStrEncoder->addItem(
+diff --git a/UI/window-basic-settings.cpp b/UI/window-basic-settings.cpp
+index ddf0adc56..9b7324ab9 100644
+--- a/UI/window-basic-settings.cpp
++++ b/UI/window-basic-settings.cpp
+@@ -3779,6 +3779,11 @@ void OBSBasicSettings::SaveOutputSettings()
+          do. This only exists to make sure that the x264 preset doesn't
+          get overwritten with empty data. */
+ 		presetType = "ApplePreset";
++	else if (encoder == SIMPLE_ENCODER_OPENH264)
++		/* The OpenH264 encoder does not have presets like the other encoders
++         do. This only exists to make sure that the x264 preset doesn't
++         get overwritten with empty data. */
++		presetType = "OpenH264Preset";
+ 	else
+ 		presetType = "Preset";
+ 
+@@ -5237,11 +5242,16 @@ void OBSBasicSettings::FillSimpleRecordingValues()
+ 	ADD_QUALITY("HQ");
+ 	ADD_QUALITY("Lossless");
+ 
+-	ui->simpleOutRecEncoder->addItem(ENCODER_STR("Software.X264.H264"),
+-					 QString(SIMPLE_ENCODER_X264));
+-	ui->simpleOutRecEncoder->addItem(
+-		ENCODER_STR("SoftwareLowCPU.X264.H264"),
+-		QString(SIMPLE_ENCODER_X264_LOWCPU));
++	ui->simpleOutRecEncoder->addItem(ENCODER_STR("Software.OpenH264.H264"),
++					 QString(SIMPLE_ENCODER_OPENH264));
++	if (EncoderAvailable("obs_x264")) {
++		ui->simpleOutRecEncoder->addItem(
++			ENCODER_STR("Software.X264.H264"),
++			QString(SIMPLE_ENCODER_X264));
++		ui->simpleOutRecEncoder->addItem(
++			ENCODER_STR("SoftwareLowCPU.X264.H264"),
++			QString(SIMPLE_ENCODER_X264_LOWCPU));
++	}
+ 	if (EncoderAvailable("obs_qsv11"))
+ 		ui->simpleOutRecEncoder->addItem(
+ 			ENCODER_STR("Hardware.QSV.H264"),
+@@ -5414,6 +5424,9 @@ void OBSBasicSettings::SimpleStreamingEncoderChanged()
+ 
+ 		defaultPreset = "balanced";
+ 		preset = curAMDAV1Preset;
++	} else if (encoder == SIMPLE_ENCODER_OPENH264) {
++		ui->simpleOutPreset->setVisible(false);
++		ui->simpleOutPresetLabel->setVisible(false);
+ 	} else {
+ 
+ #define PRESET_STR(val) \
+-- 
+2.41.0
+

diff --git a/0201-deps-Add-license-declaration-files.patch b/0201-deps-Add-license-declaration-files.patch
new file mode 100644
index 0000000..1e5173c
--- /dev/null
+++ b/0201-deps-Add-license-declaration-files.patch
@@ -0,0 +1,64 @@
+From 076024e724c4da11690735a0958b84650f449136 Mon Sep 17 00:00:00 2001
+From: Neal Gompa <neal@gompa.dev>
+Date: Tue, 29 Aug 2023 11:03:08 -0400
+Subject: [PATCH 201/204] deps: Add license declaration files
+
+---
+ deps/blake2/LICENSE.blake2                 | 19 +++++++++++++++++++
+ deps/media-playback/LICENSE.media-playback | 18 ++++++++++++++++++
+ 2 files changed, 37 insertions(+)
+ create mode 100644 deps/blake2/LICENSE.blake2
+ create mode 100644 deps/media-playback/LICENSE.media-playback
+
+diff --git a/deps/blake2/LICENSE.blake2 b/deps/blake2/LICENSE.blake2
+new file mode 100644
+index 000000000..3a8abc787
+--- /dev/null
++++ b/deps/blake2/LICENSE.blake2
+@@ -0,0 +1,19 @@
++BLAKE2 is licensed to permit usage under the terms of the CC0, the OpenSSL License,
++ or the Apache Public License 2.0 at the user's option.
++
++The license grant is reproduced in full below.
++
++/*
++   BLAKE2 reference source code package - reference C implementations
++
++   Copyright 2012, Samuel Neves <sneves@dei.uc.pt>.  You may use this under the
++   terms of the CC0, the OpenSSL Licence, or the Apache Public License 2.0, at
++   your option.  The terms of these licenses can be found at:
++
++   - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
++   - OpenSSL license   : https://www.openssl.org/source/license.html
++   - Apache 2.0        : http://www.apache.org/licenses/LICENSE-2.0
++
++   More information about the BLAKE2 hash function can be found at
++   https://blake2.net.
++*/
+diff --git a/deps/media-playback/LICENSE.media-playback b/deps/media-playback/LICENSE.media-playback
+new file mode 100644
+index 000000000..592844ea1
+--- /dev/null
++++ b/deps/media-playback/LICENSE.media-playback
+@@ -0,0 +1,18 @@
++media-playback is licensed under the ISC license. The license terms are fully
++reproduced below:
++
++/*
++ * Copyright (c) 2023 Lain Bailey <lain@obsproject.com>
++ *
++ * Permission to use, copy, modify, and distribute this software for any
++ * purpose with or without fee is hereby granted, provided that the above
++ * copyright notice and this permission notice appear in all copies.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
++ */
+-- 
+2.41.0
+

diff --git a/0202-libobs-Add-license-declaration-files.patch b/0202-libobs-Add-license-declaration-files.patch
new file mode 100644
index 0000000..4c72f28
--- /dev/null
+++ b/0202-libobs-Add-license-declaration-files.patch
@@ -0,0 +1,100 @@
+From 2a7e284c1396c68d17286d549c4ff451a12f6b4e Mon Sep 17 00:00:00 2001
+From: Neal Gompa <neal@gompa.dev>
+Date: Tue, 29 Aug 2023 11:03:29 -0400
+Subject: [PATCH 202/204] libobs: Add license declaration files
+
+---
+ libobs/graphics/libnsgif/LICENSE.libnsgif | 33 +++++++++++++++++++
+ libobs/util/simde/LICENSE.simde           | 40 +++++++++++++++++++++++
+ 2 files changed, 73 insertions(+)
+ create mode 100644 libobs/graphics/libnsgif/LICENSE.libnsgif
+ create mode 100644 libobs/util/simde/LICENSE.simde
+
+diff --git a/libobs/graphics/libnsgif/LICENSE.libnsgif b/libobs/graphics/libnsgif/LICENSE.libnsgif
+new file mode 100644
+index 000000000..9b28c0b45
+--- /dev/null
++++ b/libobs/graphics/libnsgif/LICENSE.libnsgif
+@@ -0,0 +1,33 @@
++libnsgif is licensed under the MIT license. The licensing statement
++and the full license are reproduced below.
++
++/*
++ * Copyright 2003 James Bursa <bursa@users.sourceforge.net>
++ * Copyright 2004 John Tytgat <John.Tytgat@aaug.net>
++ * Copyright 2004 Richard Wilson <richard.wilson@netsurf-browser.org>
++ * Copyright 2008 Sean Fox <dyntryx@gmail.com>
++ *
++ * This file is part of NetSurf's libnsgif, http://www.netsurf-browser.org/
++ * Licenced under the MIT License,
++ *                http://www.opensource.org/licenses/mit-license.php
++ */
++
++The MIT License
++
++Permission is hereby granted, free of charge, to any person obtaining a copy
++of this software and associated documentation files (the "Software"), to deal
++in the Software without restriction, including without limitation the rights
++to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
++copies of the Software, and to permit persons to whom the Software is
++furnished to do so, subject to the following conditions:
++
++The above copyright notice and this permission notice shall be included in
++all copies or substantial portions of the Software.
++
++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
++AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
++LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
++OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
++THE SOFTWARE.
+diff --git a/libobs/util/simde/LICENSE.simde b/libobs/util/simde/LICENSE.simde
+new file mode 100644
+index 000000000..78d482e75
+--- /dev/null
++++ b/libobs/util/simde/LICENSE.simde
+@@ -0,0 +1,40 @@
++simde is licensed as a combination of MIT and CC0 code.
++
++License notices for both are reproduced below:
++
++/* SPDX-License-Identifier: MIT
++ *
++ * Permission is hereby granted, free of charge, to any person
++ * obtaining a copy of this software and associated documentation
++ * files (the "Software"), to deal in the Software without
++ * restriction, including without limitation the rights to use, copy,
++ * modify, merge, publish, distribute, sublicense, and/or sell copies
++ * of the Software, and to permit persons to whom the Software is
++ * furnished to do so, subject to the following conditions:
++ *
++ * The above copyright notice and this permission notice shall be
++ * included in all copies or substantial portions of the Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
++ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
++ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
++ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
++ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
++ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
++ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
++ * SOFTWARE.
++ *
++ * Copyright:
++ *   2017-2020 Evan Nemerson <evan@nemerson.com>
++ */
++
++/* Portable Snippets - https://gitub.com/nemequ/portable-snippets
++ * Created by Evan Nemerson <evan@nemerson.com>
++ *
++ *   To the extent possible under law, the authors have waived all
++ *   copyright and related or neighboring rights to this code.  For
++ *   details, see the Creative Commons Zero 1.0 Universal license at
++ *   https://creativecommons.org/publicdomain/zero/1.0/
++ *
++ * SPDX-License-Identifier: CC0-1.0
++ */
+-- 
+2.41.0
+

diff --git a/0203-decklink-Add-license-declaration-files.patch b/0203-decklink-Add-license-declaration-files.patch
new file mode 100644
index 0000000..75a466b
--- /dev/null
+++ b/0203-decklink-Add-license-declaration-files.patch
@@ -0,0 +1,49 @@
+From e044e6eb8f8f8a1ebde03f5d5da91c35eab9e2a2 Mon Sep 17 00:00:00 2001
+From: Neal Gompa <neal@gompa.dev>
+Date: Tue, 29 Aug 2023 11:07:53 -0400
+Subject: [PATCH 203/204] decklink: Add license declaration files
+
+---
+ plugins/decklink/LICENSE.decklink-sdk | 30 +++++++++++++++++++++++++++
+ 1 file changed, 30 insertions(+)
+ create mode 100644 plugins/decklink/LICENSE.decklink-sdk
+
+diff --git a/plugins/decklink/LICENSE.decklink-sdk b/plugins/decklink/LICENSE.decklink-sdk
+new file mode 100644
+index 000000000..a5d1d156c
+--- /dev/null
++++ b/plugins/decklink/LICENSE.decklink-sdk
+@@ -0,0 +1,30 @@
++decklink-sdk is licensed under the Boost Software License 1.0 (BSL-1.0).
++
++The license text is reproduced in full below:
++
++/* -LICENSE-START-
++** Copyright (c) 2020 Blackmagic Design
++**
++** Permission is hereby granted, free of charge, to any person or organization
++** obtaining a copy of the software and accompanying documentation covered by
++** this license (the "Software") to use, reproduce, display, distribute,
++** execute, and transmit the Software, and to prepare derivative works of the
++** Software, and to permit third-parties to whom the Software is furnished to
++** do so, all subject to the following:
++**
++** The copyright notices in the Software and this entire statement, including
++** the above license grant, this restriction and the following disclaimer,
++** must be included in all copies of the Software, in whole or in part, and
++** all derivative works of the Software, unless such copies or derivative
++** works are solely in the form of machine-executable object code generated by
++** a source language processor.
++**
++** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
++** SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
++** FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
++** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
++** DEALINGS IN THE SOFTWARE.
++** -LICENSE-END-
++*/
+-- 
+2.41.0
+

diff --git a/0204-obs-qsv11-Add-license-declaration-file.patch b/0204-obs-qsv11-Add-license-declaration-file.patch
new file mode 100644
index 0000000..0adb40f
--- /dev/null
+++ b/0204-obs-qsv11-Add-license-declaration-file.patch
@@ -0,0 +1,78 @@
+From 57920b4e6f972cecde91e1c55680511d631af5a8 Mon Sep 17 00:00:00 2001
+From: Neal Gompa <neal@gompa.dev>
+Date: Tue, 29 Aug 2023 11:08:18 -0400
+Subject: [PATCH 204/204] obs-qsv11: Add license declaration file
+
+---
+ plugins/obs-qsv11/obs-qsv11-LICENSE.txt | 59 +++++++++++++++++++++++++
+ 1 file changed, 59 insertions(+)
+ create mode 100644 plugins/obs-qsv11/obs-qsv11-LICENSE.txt
+
+diff --git a/plugins/obs-qsv11/obs-qsv11-LICENSE.txt b/plugins/obs-qsv11/obs-qsv11-LICENSE.txt
+new file mode 100644
+index 000000000..fc8b0d7a8
+--- /dev/null
++++ b/plugins/obs-qsv11/obs-qsv11-LICENSE.txt
+@@ -0,0 +1,59 @@
++The OBS QSV plugin is licensed under either the BSD-3-Clause or GPL-2.0-only licenses.
++
++The license declaration is reproduced below:
++
++/*
++
++This is provided under a dual BSD/GPLv2 license.  When using or
++redistributing this, you may do so under either license.
++
++GPL LICENSE SUMMARY
++
++Copyright(c) Oct. 2015 Intel Corporation.
++
++This program is free software; you can redistribute it and/or modify
++it under the terms of version 2 of the GNU General Public License as
++published by the Free Software Foundation.
++
++This program is distributed in the hope that it will be useful, but
++WITHOUT ANY WARRANTY; without even the implied warranty of
++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++General Public License for more details.
++
++Contact Information:
++
++Seung-Woo Kim, seung-woo.kim@intel.com
++705 5th Ave S #500, Seattle, WA 98104
++
++BSD LICENSE
++
++Copyright(c) <date> Intel Corporation.
++
++Redistribution and use in source and binary forms, with or without
++modification, are permitted provided that the following conditions
++are met:
++
++* Redistributions of source code must retain the above copyright
++notice, this list of conditions and the following disclaimer.
++
++* Redistributions in binary form must reproduce the above copyright
++notice, this list of conditions and the following disclaimer in
++the documentation and/or other materials provided with the
++distribution.
++
++* Neither the name of Intel Corporation nor the names of its
++contributors may be used to endorse or promote products derived
++from this software without specific prior written permission.
++
++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
++"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
++LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
++A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
++OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
++SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
++LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
++DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
++THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
++OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++*/
+-- 
+2.41.0
+

diff --git a/obs-studio-deps-Add-license-declaration-files.patch b/obs-studio-deps-Add-license-declaration-files.patch
deleted file mode 100644
index d1e460c..0000000
--- a/obs-studio-deps-Add-license-declaration-files.patch
+++ /dev/null
@@ -1,218 +0,0 @@
-From b6be0b4bf5b0b2f26c8143641881cde23ac8ba9c Mon Sep 17 00:00:00 2001
-From: Neal Gompa <neal@gompa.dev>
-Date: Wed, 26 Apr 2023 07:56:35 -0400
-Subject: [PATCH 1/2] deps: Add license declaration files
-
----
- deps/blake2/LICENSE.blake2                 | 19 ++++++++++
- deps/libff/LICENSE.libff                   | 18 ++++++++++
- deps/media-playback/LICENSE.media-playback | 19 ++++++++++
- libobs/graphics/libnsgif/LICENSE.libnsgif  | 33 ++++++++++++++++++
- libobs/util/simde/LICENSE.simde            | 40 ++++++++++++++++++++++
- plugins/decklink/LICENSE.decklink-sdk      | 30 ++++++++++++++++
- 6 files changed, 159 insertions(+)
- create mode 100644 deps/blake2/LICENSE.blake2
- create mode 100644 deps/libff/LICENSE.libff
- create mode 100644 deps/media-playback/LICENSE.media-playback
- create mode 100644 libobs/graphics/libnsgif/LICENSE.libnsgif
- create mode 100644 libobs/util/simde/LICENSE.simde
- create mode 100644 plugins/decklink/LICENSE.decklink-sdk
-
-diff --git a/deps/blake2/LICENSE.blake2 b/deps/blake2/LICENSE.blake2
-new file mode 100644
-index 000000000..3a8abc787
---- /dev/null
-+++ b/deps/blake2/LICENSE.blake2
-@@ -0,0 +1,19 @@
-+BLAKE2 is licensed to permit usage under the terms of the CC0, the OpenSSL License,
-+ or the Apache Public License 2.0 at the user's option.
-+
-+The license grant is reproduced in full below.
-+
-+/*
-+   BLAKE2 reference source code package - reference C implementations
-+
-+   Copyright 2012, Samuel Neves <sneves@dei.uc.pt>.  You may use this under the
-+   terms of the CC0, the OpenSSL Licence, or the Apache Public License 2.0, at
-+   your option.  The terms of these licenses can be found at:
-+
-+   - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
-+   - OpenSSL license   : https://www.openssl.org/source/license.html
-+   - Apache 2.0        : http://www.apache.org/licenses/LICENSE-2.0
-+
-+   More information about the BLAKE2 hash function can be found at
-+   https://blake2.net.
-+*/
-diff --git a/deps/libff/LICENSE.libff b/deps/libff/LICENSE.libff
-new file mode 100644
-index 000000000..b6f51157a
---- /dev/null
-+++ b/deps/libff/LICENSE.libff
-@@ -0,0 +1,18 @@
-+libff is licensed under the ISC license. The license terms are fully
-+reproduced below:
-+
-+/*
-+ * Copyright (c) 2015 John R. Bradley <jrb@turrettech.com>
-+ *
-+ * Permission to use, copy, modify, and distribute this software for any
-+ * purpose with or without fee is hereby granted, provided that the above
-+ * copyright notice and this permission notice appear in all copies.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
-+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-+ */
-diff --git a/deps/media-playback/LICENSE.media-playback b/deps/media-playback/LICENSE.media-playback
-new file mode 100644
-index 000000000..17d74f4b3
---- /dev/null
-+++ b/deps/media-playback/LICENSE.media-playback
-@@ -0,0 +1,19 @@
-+media-playback is licensed under the ISC license. The license terms are fully
-+reproduced below:
-+
-+
-+/*
-+ * Copyright (c) 2023 Hugh Bailey <obs.jim@gmail.com>
-+ *
-+ * Permission to use, copy, modify, and distribute this software for any
-+ * purpose with or without fee is hereby granted, provided that the above
-+ * copyright notice and this permission notice appear in all copies.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
-+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-+ */
-diff --git a/libobs/graphics/libnsgif/LICENSE.libnsgif b/libobs/graphics/libnsgif/LICENSE.libnsgif
-new file mode 100644
-index 000000000..9b28c0b45
---- /dev/null
-+++ b/libobs/graphics/libnsgif/LICENSE.libnsgif
-@@ -0,0 +1,33 @@
-+libnsgif is licensed under the MIT license. The licensing statement
-+and the full license are reproduced below.
-+
-+/*
-+ * Copyright 2003 James Bursa <bursa@users.sourceforge.net>
-+ * Copyright 2004 John Tytgat <John.Tytgat@aaug.net>
-+ * Copyright 2004 Richard Wilson <richard.wilson@netsurf-browser.org>
-+ * Copyright 2008 Sean Fox <dyntryx@gmail.com>
-+ *
-+ * This file is part of NetSurf's libnsgif, http://www.netsurf-browser.org/
-+ * Licenced under the MIT License,
-+ *                http://www.opensource.org/licenses/mit-license.php
-+ */
-+
-+The MIT License
-+
-+Permission is hereby granted, free of charge, to any person obtaining a copy
-+of this software and associated documentation files (the "Software"), to deal
-+in the Software without restriction, including without limitation the rights
-+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-+copies of the Software, and to permit persons to whom the Software is
-+furnished to do so, subject to the following conditions:
-+
-+The above copyright notice and this permission notice shall be included in
-+all copies or substantial portions of the Software.
-+
-+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-+THE SOFTWARE.
-diff --git a/libobs/util/simde/LICENSE.simde b/libobs/util/simde/LICENSE.simde
-new file mode 100644
-index 000000000..78d482e75
---- /dev/null
-+++ b/libobs/util/simde/LICENSE.simde
-@@ -0,0 +1,40 @@
-+simde is licensed as a combination of MIT and CC0 code.
-+
-+License notices for both are reproduced below:
-+
-+/* SPDX-License-Identifier: MIT
-+ *
-+ * Permission is hereby granted, free of charge, to any person
-+ * obtaining a copy of this software and associated documentation
-+ * files (the "Software"), to deal in the Software without
-+ * restriction, including without limitation the rights to use, copy,
-+ * modify, merge, publish, distribute, sublicense, and/or sell copies
-+ * of the Software, and to permit persons to whom the Software is
-+ * furnished to do so, subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice shall be
-+ * included in all copies or substantial portions of the Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
-+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
-+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
-+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-+ * SOFTWARE.
-+ *
-+ * Copyright:
-+ *   2017-2020 Evan Nemerson <evan@nemerson.com>
-+ */
-+
-+/* Portable Snippets - https://gitub.com/nemequ/portable-snippets
-+ * Created by Evan Nemerson <evan@nemerson.com>
-+ *
-+ *   To the extent possible under law, the authors have waived all
-+ *   copyright and related or neighboring rights to this code.  For
-+ *   details, see the Creative Commons Zero 1.0 Universal license at
-+ *   https://creativecommons.org/publicdomain/zero/1.0/
-+ *
-+ * SPDX-License-Identifier: CC0-1.0
-+ */
-diff --git a/plugins/decklink/LICENSE.decklink-sdk b/plugins/decklink/LICENSE.decklink-sdk
-new file mode 100644
-index 000000000..d320d805b
---- /dev/null
-+++ b/plugins/decklink/LICENSE.decklink-sdk
-@@ -0,0 +1,30 @@
-+decklink-sdk is licensed under to Boost Software License 1.0 (BSL-1.0).
-+
-+The license text is reproduced in full below:
-+
-+/* -LICENSE-START-
-+** Copyright (c) 2020 Blackmagic Design
-+**
-+** Permission is hereby granted, free of charge, to any person or organization
-+** obtaining a copy of the software and accompanying documentation covered by
-+** this license (the "Software") to use, reproduce, display, distribute,
-+** execute, and transmit the Software, and to prepare derivative works of the
-+** Software, and to permit third-parties to whom the Software is furnished to
-+** do so, all subject to the following:
-+**
-+** The copyright notices in the Software and this entire statement, including
-+** the above license grant, this restriction and the following disclaimer,
-+** must be included in all copies of the Software, in whole or in part, and
-+** all derivative works of the Software, unless such copies or derivative
-+** works are solely in the form of machine-executable object code generated by
-+** a source language processor.
-+**
-+** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
-+** SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
-+** FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
-+** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-+** DEALINGS IN THE SOFTWARE.
-+** -LICENSE-END-
-+*/
--- 
-2.40.0
-

diff --git a/obs-studio-obs-qsv11-Add-license-declaration-file.patch b/obs-studio-obs-qsv11-Add-license-declaration-file.patch
deleted file mode 100644
index 0504446..0000000
--- a/obs-studio-obs-qsv11-Add-license-declaration-file.patch
+++ /dev/null
@@ -1,79 +0,0 @@
-From fbfa25ade86c26088333b3c5e6c39d4a61fc748f Mon Sep 17 00:00:00 2001
-From: Neal Gompa <neal@gompa.dev>
-Date: Wed, 26 Apr 2023 07:56:42 -0400
-Subject: [PATCH 2/2] obs-qsv11: Add license declaration file
-
----
- plugins/obs-qsv11/obs-qsv11-LICENSE.txt | 60 +++++++++++++++++++++++++
- 1 file changed, 60 insertions(+)
- create mode 100644 plugins/obs-qsv11/obs-qsv11-LICENSE.txt
-
-diff --git a/plugins/obs-qsv11/obs-qsv11-LICENSE.txt b/plugins/obs-qsv11/obs-qsv11-LICENSE.txt
-new file mode 100644
-index 000000000..2e4f30941
---- /dev/null
-+++ b/plugins/obs-qsv11/obs-qsv11-LICENSE.txt
-@@ -0,0 +1,60 @@
-+The OBS QSV plugin is licensed under either the BSD-3-Clause or GPL-2.0-only licenses.
-+
-+The license declaration is reproduced below:
-+
-+/*
-+
-+This is provided under a dual BSD/GPLv2 license.  When using or
-+redistributing this, you may do so under either license.
-+
-+GPL LICENSE SUMMARY
-+
-+Copyright(c) Oct. 2015 Intel Corporation.
-+
-+This program is free software; you can redistribute it and/or modify
-+it under the terms of version 2 of the GNU General Public License as
-+published by the Free Software Foundation.
-+
-+This program is distributed in the hope that it will be useful, but
-+WITHOUT ANY WARRANTY; without even the implied warranty of
-+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-+General Public License for more details.
-+
-+Contact Information:
-+
-+Seung-Woo Kim, seung-woo.kim@intel.com
-+705 5th Ave S #500, Seattle, WA 98104
-+
-+BSD LICENSE
-+
-+Copyright(c) <date> Intel Corporation.
-+
-+Redistribution and use in source and binary forms, with or without
-+modification, are permitted provided that the following conditions
-+are met:
-+
-+* Redistributions of source code must retain the above copyright
-+notice, this list of conditions and the following disclaimer.
-+
-+* Redistributions in binary form must reproduce the above copyright
-+notice, this list of conditions and the following disclaimer in
-+the documentation and/or other materials provided with the
-+distribution.
-+
-+* Neither the name of Intel Corporation nor the names of its
-+contributors may be used to endorse or promote products derived
-+from this software without specific prior written permission.
-+
-+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-+*/
-+
--- 
-2.40.0
-

diff --git a/obs-studio.spec b/obs-studio.spec
index c3a7ca1..9a0437b 100644
--- a/obs-studio.spec
+++ b/obs-studio.spec
@@ -16,20 +16,20 @@
 %global openh264_soversion 7
 
 
-%global obswebsocket_version 5.2.3
+%global obswebsocket_version 5.3.0
 
 #global commit ad859a3f66daac0d30eebcc9b07b0c2004fb6040
 #global snapdate 202303261743
 #global shortcommit %(c=%{commit}; echo ${c:0:7})
 
 Name:           obs-studio
-Version:        29.1.3
-Release:        4%{?dist}
+Version:        30.0.0~beta3
+Release:        1%{?dist}
 Summary:        Open Broadcaster Software Studio
 
 # OBS itself is GPL-2.0-or-later, while various plugin dependencies are of various other licenses
 # The licenses for those dependencies are captured with the bundled provides statements
-License:        GPL-2.0-or-later and ISC and MIT and BSD-1-Clause and BSD-2-Clause and BSD-3-Clause and BSL-1.0 and LGPL-2.1-or-later and CC0-1.0 and (CC0-1.0 or OpenSSL or Apache-2.0) and LicenseRef-Fedora-Public-Domain and (BSD-3-Clause or GPL-2.0-only)
+License:        GPL-2.0-or-later and MIT and BSD-1-Clause and BSD-2-Clause and BSD-3-Clause and BSL-1.0 and LGPL-2.1-or-later and CC0-1.0 and (CC0-1.0 or OpenSSL or Apache-2.0) and LicenseRef-Fedora-Public-Domain and (BSD-3-Clause or GPL-2.0-only)
 URL:            https://obsproject.com/
 %if 0%{?snapdate}
 Source0:        https://github.com/obsproject/obs-studio/archive/%{commit}/%{name}-%{commit}.tar.gz
@@ -42,20 +42,22 @@ Source1:        https://github.com/obsproject/obs-websocket/archive/%{obswebsock
 
 # Proposed upstream
 ## From: https://github.com/obsproject/obs-studio/pull/8529
-Patch0101:      0001-UI-Consistently-reference-the-software-H264-encoder-.patch
-Patch0102:      0002-obs-ffmpeg-Add-initial-support-for-the-OpenH264-H.26.patch
-Patch0103:      0003-UI-Add-support-for-OpenH264-as-the-worst-case-fallba.patch
+Patch0101:      0101-UI-Consistently-reference-the-software-H264-encoder-.patch
+Patch0102:      0102-obs-ffmpeg-Add-initial-support-for-the-OpenH264-H.26.patch
+Patch0103:      0103-UI-Add-support-for-OpenH264-as-the-worst-case-fallba.patch
+
+## From: https://github.com/obsproject/obs-studio/pull/8777
+Patch0201:      0201-deps-Add-license-declaration-files.patch
+Patch0202:      0202-libobs-Add-license-declaration-files.patch
+Patch0203:      0203-decklink-Add-license-declaration-files.patch
+Patch0204:      0204-obs-qsv11-Add-license-declaration-file.patch
 
 
 # Downstream Fedora patches
 ## Use system qrcodegencpp
-Patch1001:      obs-studio-websocket-use-system-qrcodegencpp.patch
+#Patch1001:      obs-studio-websocket-use-system-qrcodegencpp.patch
 ## Use fdk-aac by default
 Patch1002:      obs-studio-UI-use-fdk-aac-by-default.patch
-## Add license declarations for bundled deps
-Patch9001:      obs-studio-deps-Add-license-declaration-files.patch
-## Add license declaration for obs-qsv11
-Patch9002:      obs-studio-obs-qsv11-Add-license-declaration-file.patch
 
 
 BuildRequires:  gcc
@@ -73,6 +75,7 @@ BuildRequires:  freetype-devel
 BuildRequires:  jansson-devel >= 2.5
 BuildRequires:  json-devel
 BuildRequires:  libcurl-devel
+BuildRequires:  libdatachannel-devel
 BuildRequires:  libdrm-devel
 BuildRequires:  libGL-devel
 BuildRequires:  libglvnd-devel
@@ -90,6 +93,7 @@ BuildRequires:  libxkbcommon-devel
 BuildRequires:  luajit-devel
 %endif
 BuildRequires:  mbedtls-devel
+BuildRequires:  oneVPL-devel
 BuildRequires:  pciutils-devel
 BuildRequires:  pipewire-devel
 BuildRequires:  pipewire-jack-audio-connection-kit-devel
@@ -141,8 +145,6 @@ Provides:      bundled(blake2)
 Provides:      bundled(json11)
 ## License: MIT
 Provides:      bundled(libcaption)
-## License: ISC
-Provides:      bundled(libff)
 ## License: BSD-1-Clause
 Provides:      bundled(uthash)
 ## License: BSD-3-Clause
@@ -223,7 +225,6 @@ cp deps/libcaption/LICENSE.txt .fedora-rpm/licenses/deps/libcaption-LICENSE.txt
 cp plugins/obs-qsv11/QSV11-License-Clarification-Email.txt .fedora-rpm/licenses/plugins/QSV11-License-Clarification-Email.txt
 cp deps/uthash/uthash/LICENSE .fedora-rpm/licenses/deps/uthash-LICENSE
 cp deps/blake2/LICENSE.blake2 .fedora-rpm/licenses/deps/
-cp deps/libff/LICENSE.libff .fedora-rpm/licenses/deps/
 cp deps/media-playback/LICENSE.media-playback .fedora-rpm/licenses/deps/
 cp libobs/graphics/libnsgif/LICENSE.libnsgif .fedora-rpm/licenses/deps/
 cp libobs/util/simde/LICENSE.simde .fedora-rpm/licenses/deps/
@@ -252,10 +253,6 @@ cp plugins/obs-qsv11/obs-qsv11-LICENSE.txt .fedora-rpm/licenses/plugins/
 %install
 %cmake_install
 
-# Add missing files to enable the build of obs-ndi
-install -Dm644 UI/obs-frontend-api/obs-frontend-api.h %{buildroot}%{_includedir}/obs/
-install -Dm644 cmake/external/ObsPluginHelpers.cmake %{buildroot}%{_libdir}/cmake/libobs/
-
 # Work around broken libobs.pc file...
 # Cf. https://github.com/obsproject/obs-studio/issues/7972
 sed -e 's|^Cflags: .*|Cflags: -I${includedir} -DHAVE_OBSCONFIG_H|' -i %{buildroot}%{_libdir}/pkgconfig/libobs.pc
@@ -302,6 +299,9 @@ appstream-util validate-relax --nonet %{buildroot}%{_datadir}/metainfo/*.appdata
 
 
 %changelog
+* Mon Sep 11 2023 Neal Gompa <ngompa@fedoraproject.org> - 30.0.0~beta3-1
+- Rebase to 30.0.0~beta3
+
 * Fri Sep 08 2023 Neal Gompa <ngompa@fedoraproject.org> - 29.1.3-4
 - Add obs-plugins libexecdir to libs subpackage
 

diff --git a/sources b/sources
index c635c9c..ce06999 100644
--- a/sources
+++ b/sources
@@ -1,2 +1,2 @@
-SHA512 (obs-studio-29.1.3.tar.gz) = 563a9b71ebe273b604807b9c43be8bde58fb326e8a0b741afb84a481a99176c96bf63da2aa26b6dcc026573b7fb0bf53e0a296e2db0b93c28f0d4710cd7cf019
-SHA512 (obs-websocket-5.2.3.tar.gz) = 76e25bc0a3eb3f6d11b123b5b193544e409cd794b4b38de4ddd634a34cfbdba023c181b81b467fb31d7b4dff17d9b66781be6f1cf0e7e66042868078022d03af
+SHA512 (obs-studio-30.0.0-beta3.tar.gz) = 623099dfe5ff031441d7b2b169c0712b61b0dd74c848eae231e8937cbaa991e5ad92bb8a0bfd1a7ba40e193319ea0612f3290fe507739d6cafd2fc7f42986fa4
+SHA512 (obs-websocket-5.3.0.tar.gz) = 814fa721dce2e96e0ced63d3aac3db29fb051244937deea8a708cf621903710fabeec92b78b7ce304e8e15d7ec9fb38ded11edf56f6aa8b23d416b0fb87b5994

^ permalink raw reply related	[flat|nested] only message in thread

only message in thread, other threads:[~2026-07-20 19:39 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-07-20 19:39 [rpms/obs-studio] epel9-next: Rebase to 30.0.0~beta3 Neal Gompa

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox