Skip to content

Commit

Permalink
UI: Add support for OpenH264 as the worst-case fallback
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
Conan-Kudo committed Mar 26, 2023
1 parent d86db07 commit 6164cb4
Show file tree
Hide file tree
Showing 10 changed files with 111 additions and 47 deletions.
1 change: 1 addition & 0 deletions UI/data/locale/en-US.ini
Original file line number Diff line number Diff line change
Expand Up @@ -979,6 +979,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)"
Expand Down
50 changes: 35 additions & 15 deletions UI/window-basic-auto-config-test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down Expand Up @@ -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());
Expand Down Expand Up @@ -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 =
Expand All @@ -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");
}

/* -----------------------------------*/
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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) {
Expand All @@ -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")
Expand Down Expand Up @@ -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:
Expand All @@ -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 * {
Expand Down
15 changes: 14 additions & 1 deletion UI/window-basic-auto-config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}
};

Expand Down
3 changes: 3 additions & 0 deletions UI/window-basic-auto-config.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ class AutoConfig : public QWizard {
};

enum class Encoder {
OpenH264,
x264,
NVENC,
QSV,
Expand Down Expand Up @@ -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;
Expand All @@ -106,6 +108,7 @@ class AutoConfig : public QWizard {
int specificFPSNum = 0;
int specificFPSDen = 0;

void TestSoftwareEncoding();
void TestHardwareEncoding();
bool CanTestServer(const char *server);

Expand Down
6 changes: 4 additions & 2 deletions UI/window-basic-main-outputs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -527,7 +527,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";
Expand Down Expand Up @@ -561,7 +563,7 @@ const char *get_simple_output_encoder(const char *encoder)
#endif
}

return "obs_x264";
return "ffmpeg_openh264";
}

void SimpleOutput::LoadRecordingPreset()
Expand Down
34 changes: 21 additions & 13 deletions UI/window-basic-main-profiles.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -794,7 +794,7 @@ void OBSBasic::ChangeProfile()

Auth::Load();

CheckForSimpleModeX264Fallback();
CheckForSimpleModeH264Fallback();

blog(LOG_INFO, "Switched to profile '%s' (%s)", newName, newDir);
blog(LOG_INFO, "------------------------------------------------");
Expand All @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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
Expand Down
15 changes: 9 additions & 6 deletions UI/window-basic-main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1542,7 +1542,8 @@ 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");
config_set_default_string(basicConfig, "AdvOut", "Encoder",
"ffmpeg_openh264");

config_set_default_string(basicConfig, "AdvOut", "RecType", "Standard");

Expand Down Expand Up @@ -1674,12 +1675,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"))
Expand Down Expand Up @@ -1960,7 +1963,7 @@ void OBSBasic::OBSInit()

InitBasicConfigDefaults2();

CheckForSimpleModeX264Fallback();
CheckForSimpleModeH264Fallback();

blog(LOG_INFO, STARTUP_SEPARATOR);

Expand Down
3 changes: 2 additions & 1 deletion UI/window-basic-main.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -434,7 +435,7 @@ class OBSBasic : public OBSMainWindow {
void DeleteProfile(const char *profile_name, const char *profile_dir);
void RefreshProfiles();
void ChangeProfile();
void CheckForSimpleModeX264Fallback();
void CheckForSimpleModeH264Fallback();

void SaveProjectNow();

Expand Down

0 comments on commit 6164cb4

Please sign in to comment.