From 29ae00e4afe3158ba2dd5281b97334e63d4d72c8 Mon Sep 17 00:00:00 2001 From: gxalpha Date: Thu, 23 Jun 2022 02:46:03 +0200 Subject: [PATCH] UI: Add Apple H.264 hardware encoder to simple mode Adds the Apple Silicon hardware encoder as a simple mode option. For recordings this only requires being on Apple Silicon (since we use the Constant Quality setting), while for streaming it requires the user to be on macOS 13 or newer (since we're using CBR). --- UI/data/locale/en-US.ini | 1 + UI/forms/OBSBasicSettings.ui | 2 +- UI/window-basic-main-outputs.cpp | 21 ++++++++++++++++++++ UI/window-basic-main-profiles.cpp | 11 +++++++++++ UI/window-basic-main.hpp | 1 + UI/window-basic-settings.cpp | 33 +++++++++++++++++++++++++++++++ 6 files changed, 68 insertions(+), 1 deletion(-) diff --git a/UI/data/locale/en-US.ini b/UI/data/locale/en-US.ini index 8109863cc..0296cbc4c 100644 --- a/UI/data/locale/en-US.ini +++ b/UI/data/locale/en-US.ini @@ -897,6 +897,7 @@ Basic.Settings.Output.Simple.Encoder.Hardware.QSV.H264="Hardware (QSV, H.264)" Basic.Settings.Output.Simple.Encoder.Hardware.AMD.H264="Hardware (AMD, H.264)" Basic.Settings.Output.Simple.Encoder.Hardware.NVENC.H264="Hardware (NVENC, H.264)" 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.SoftwareLowCPU="Software (x264 low CPU usage preset, increases file size)" Basic.Settings.Output.Simple.TwitchVodTrack="Twitch VOD Track (Uses Track 2)" Basic.Settings.Output.Warn.EnforceResolutionFPS.Title="Incompatible Resolution/Framerate" diff --git a/UI/forms/OBSBasicSettings.ui b/UI/forms/OBSBasicSettings.ui index d4b516bc3..5f17c0af6 100644 --- a/UI/forms/OBSBasicSettings.ui +++ b/UI/forms/OBSBasicSettings.ui @@ -1610,7 +1610,7 @@ - + true diff --git a/UI/window-basic-main-outputs.cpp b/UI/window-basic-main-outputs.cpp index 0035e7ca9..82ad80c20 100644 --- a/UI/window-basic-main-outputs.cpp +++ b/UI/window-basic-main-outputs.cpp @@ -289,6 +289,7 @@ struct SimpleOutput : BasicOutputHandler { void UpdateRecordingSettings_nvenc_hevc(int cqp); #endif void UpdateRecordingSettings_amd_cqp(int cqp); + void UpdateRecordingSettings_apple(int quality); void UpdateRecordingSettings(); void UpdateRecordingAudioSettings(); virtual void Update() override; @@ -402,6 +403,9 @@ void SimpleOutput::LoadRecordingPreset() : "ffmpeg_hevc_nvenc"; LoadRecordingPreset_Lossy(id); #endif + } else if (strcmp(encoder, SIMPLE_ENCODER_APPLE_H264) == 0) { + LoadRecordingPreset_Lossy( + "com.apple.videotoolbox.videoencoder.ave.avc"); } usingRecordingPreset = true; @@ -438,6 +442,10 @@ SimpleOutput::SimpleOutput(OBSBasic *main_) : BasicOutputHandler(main_) LoadStreamingPreset_Lossy(id); #endif + } else if (strcmp(encoder, SIMPLE_ENCODER_APPLE_H264) == 0) { + LoadStreamingPreset_Lossy( + "com.apple.videotoolbox.videoencoder.ave.avc"); + } else { LoadStreamingPreset_Lossy("obs_x264"); } @@ -690,6 +698,16 @@ void SimpleOutput::UpdateRecordingSettings_nvenc_hevc(int cqp) } #endif +void SimpleOutput::UpdateRecordingSettings_apple(int quality) +{ + OBSDataAutoRelease settings = obs_data_create(); + obs_data_set_string(settings, "rate_control", "CRF"); + obs_data_set_string(settings, "profile", "high"); + obs_data_set_int(settings, "quality", quality); + + obs_encoder_update(videoRecording, settings); +} + void SimpleOutput::UpdateStreamingSettings_amd(obs_data_t *settings, int bitrate) { @@ -754,6 +772,9 @@ void SimpleOutput::UpdateRecordingSettings() } else if (videoEncoder == SIMPLE_ENCODER_NVENC_HEVC) { UpdateRecordingSettings_nvenc_hevc(crf); #endif + } else if (videoEncoder == SIMPLE_ENCODER_APPLE_H264) { + /* These are magic numbers. 0 - 100, more is better. */ + UpdateRecordingSettings_apple(ultra_hq ? 70 : 50); } UpdateRecordingAudioSettings(); } diff --git a/UI/window-basic-main-profiles.cpp b/UI/window-basic-main-profiles.cpp index 04780a142..5c6ed768a 100644 --- a/UI/window-basic-main-profiles.cpp +++ b/UI/window-basic-main-profiles.cpp @@ -821,6 +821,7 @@ void OBSBasic::CheckForSimpleModeX264Fallback() #ifdef ENABLE_HEVC bool nve_hevc_supported = false; #endif + bool apple_supported = false; bool changed = false; size_t idx = 0; const char *id; @@ -836,6 +837,10 @@ void OBSBasic::CheckForSimpleModeX264Fallback() else if (strcmp(id, "ffmpeg_hevc_nvenc") == 0) nve_hevc_supported = true; #endif + else if (strcmp(id, + "com.apple.videotoolbox.videoencoder.ave.avc") == + 0) + apple_supported = true; } auto CheckEncoder = [&](const char *&name) { @@ -865,6 +870,12 @@ void OBSBasic::CheckForSimpleModeX264Fallback() name = SIMPLE_ENCODER_X264; return false; } + } else if (strcmp(name, SIMPLE_ENCODER_APPLE_H264) == 0) { + if (!apple_supported) { + changed = true; + name = SIMPLE_ENCODER_X264; + return false; + } } return true; diff --git a/UI/window-basic-main.hpp b/UI/window-basic-main.hpp index 4ab99049f..4a91ceb31 100644 --- a/UI/window-basic-main.hpp +++ b/UI/window-basic-main.hpp @@ -70,6 +70,7 @@ class OBSBasicStats; #define SIMPLE_ENCODER_NVENC_HEVC "nvenc_hevc" #endif #define SIMPLE_ENCODER_AMD "amd" +#define SIMPLE_ENCODER_APPLE_H264 "apple_h264" #define PREVIEW_EDGE_SIZE 10 diff --git a/UI/window-basic-settings.cpp b/UI/window-basic-settings.cpp index e99707fca..3853cf116 100644 --- a/UI/window-basic-settings.cpp +++ b/UI/window-basic-settings.cpp @@ -3542,6 +3542,11 @@ void OBSBasicSettings::SaveOutputSettings() #endif else if (encoder == SIMPLE_ENCODER_AMD) presetType = "AMDPreset"; + else if (encoder == SIMPLE_ENCODER_APPLE_H264) + /* The Apple encoders don't 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 = "ApplePreset"; else presetType = "Preset"; @@ -4768,6 +4773,14 @@ void OBSBasicSettings::FillSimpleRecordingValues() ui->simpleOutRecEncoder->addItem( ENCODER_STR("Hardware.AMD.H264"), QString(SIMPLE_ENCODER_AMD)); + if (EncoderAvailable("com.apple.videotoolbox.videoencoder.ave.avc") +#ifndef __aarch64__ + && os_get_emulation_status() == true +#endif + ) + ui->simpleOutRecEncoder->addItem( + ENCODER_STR("Hardware.Apple.H264"), + QString(SIMPLE_ENCODER_APPLE_H264)); #undef ADD_QUALITY } @@ -4793,6 +4806,18 @@ void OBSBasicSettings::FillSimpleStreamingValues() ui->simpleOutStrEncoder->addItem( ENCODER_STR("Hardware.AMD.H264"), QString(SIMPLE_ENCODER_AMD)); +/* Preprocessor guard required for the macOS version check */ +#ifdef __APPLE__ + if (EncoderAvailable("com.apple.videotoolbox.videoencoder.ave.avc") +#ifndef __aarch64__ + && os_get_emulation_status() == true +#endif + ) + if (__builtin_available(macOS 13.0, *)) + ui->simpleOutStrEncoder->addItem( + ENCODER_STR("Hardware.Apple.H264"), + QString(SIMPLE_ENCODER_APPLE_H264)); +#endif #undef ENCODER_STR } @@ -4835,6 +4860,9 @@ void OBSBasicSettings::SimpleStreamingEncoderChanged() QString preset; const char *defaultPreset = nullptr; + ui->simpleOutAdvanced->setVisible(true); + ui->simpleOutPresetLabel->setVisible(true); + ui->simpleOutPreset->setVisible(true); ui->simpleOutPreset->clear(); if (encoder == SIMPLE_ENCODER_QSV) { @@ -4906,6 +4934,11 @@ void OBSBasicSettings::SimpleStreamingEncoderChanged() defaultPreset = "balanced"; preset = curAMDPreset; + } else if (encoder == SIMPLE_ENCODER_APPLE_H264) { + ui->simpleOutAdvanced->setChecked(false); + ui->simpleOutAdvanced->setVisible(false); + ui->simpleOutPreset->setVisible(false); + ui->simpleOutPresetLabel->setVisible(false); } else { #define PRESET_STR(val) \