UI: Add virtual camera to UI
Adds a virtual camera button to the main user interface. If virtual camera is not installed, it will not add the button. On Windows, it detects whether the virtual camera filters are properly registered, and will only add the button if the virtual camera filter is confirmed registered. Also adds a virtual camera option to the auto-configuration wizard, which will just simply set the user's resolution/scale to 1920x1080 at 30 FPS.master
parent
6377fe3177
commit
a72a52fa38
|
@ -150,6 +150,7 @@ Basic.AutoConfig.StartPage="Usage Information"
|
||||||
Basic.AutoConfig.StartPage.SubTitle="Specify what you want to use the program for"
|
Basic.AutoConfig.StartPage.SubTitle="Specify what you want to use the program for"
|
||||||
Basic.AutoConfig.StartPage.PrioritizeStreaming="Optimize for streaming, recording is secondary"
|
Basic.AutoConfig.StartPage.PrioritizeStreaming="Optimize for streaming, recording is secondary"
|
||||||
Basic.AutoConfig.StartPage.PrioritizeRecording="Optimize just for recording, I will not be streaming"
|
Basic.AutoConfig.StartPage.PrioritizeRecording="Optimize just for recording, I will not be streaming"
|
||||||
|
Basic.AutoConfig.StartPage.PrioritizeVirtualCam="I will only be using the virtual camera"
|
||||||
Basic.AutoConfig.VideoPage="Video Settings"
|
Basic.AutoConfig.VideoPage="Video Settings"
|
||||||
Basic.AutoConfig.VideoPage.SubTitle="Specify the desired video settings you would like to use"
|
Basic.AutoConfig.VideoPage.SubTitle="Specify the desired video settings you would like to use"
|
||||||
Basic.AutoConfig.VideoPage.BaseResolution.UseCurrent="Use Current (%1x%2)"
|
Basic.AutoConfig.VideoPage.BaseResolution.UseCurrent="Use Current (%1x%2)"
|
||||||
|
@ -520,6 +521,7 @@ Basic.Main.StartRecording="Start Recording"
|
||||||
Basic.Main.StartReplayBuffer="Start Replay Buffer"
|
Basic.Main.StartReplayBuffer="Start Replay Buffer"
|
||||||
Basic.Main.SaveReplay="Save Replay"
|
Basic.Main.SaveReplay="Save Replay"
|
||||||
Basic.Main.StartStreaming="Start Streaming"
|
Basic.Main.StartStreaming="Start Streaming"
|
||||||
|
Basic.Main.StartVirtualCam="Start Virtual Camera"
|
||||||
Basic.Main.StopRecording="Stop Recording"
|
Basic.Main.StopRecording="Stop Recording"
|
||||||
Basic.Main.PauseRecording="Pause Recording"
|
Basic.Main.PauseRecording="Pause Recording"
|
||||||
Basic.Main.UnpauseRecording="Unpause Recording"
|
Basic.Main.UnpauseRecording="Unpause Recording"
|
||||||
|
@ -529,6 +531,7 @@ Basic.Main.StoppingReplayBuffer="Stopping Replay Buffer..."
|
||||||
Basic.Main.StopStreaming="Stop Streaming"
|
Basic.Main.StopStreaming="Stop Streaming"
|
||||||
Basic.Main.StoppingStreaming="Stopping Stream..."
|
Basic.Main.StoppingStreaming="Stopping Stream..."
|
||||||
Basic.Main.ForceStopStreaming="Stop Streaming (discard delay)"
|
Basic.Main.ForceStopStreaming="Stop Streaming (discard delay)"
|
||||||
|
Basic.Main.StopVirtualCam="Stop Virtual Camera"
|
||||||
Basic.Main.Group="Group %1"
|
Basic.Main.Group="Group %1"
|
||||||
Basic.Main.GroupItems="Group Selected Items"
|
Basic.Main.GroupItems="Group Selected Items"
|
||||||
Basic.Main.Ungroup="Ungroup"
|
Basic.Main.Ungroup="Ungroup"
|
||||||
|
|
|
@ -373,6 +373,14 @@ Section -FinishSection
|
||||||
ClearErrors
|
ClearErrors
|
||||||
WriteRegDWORD HKLM "Software\Khronos\Vulkan\ImplicitLayers" "$APPDATA\obs-studio-hook\obs-vulkan32.json" 0
|
WriteRegDWORD HKLM "Software\Khronos\Vulkan\ImplicitLayers" "$APPDATA\obs-studio-hook\obs-vulkan32.json" 0
|
||||||
|
|
||||||
|
# ---------------------------------------
|
||||||
|
# Register virtual camera dlls
|
||||||
|
|
||||||
|
Exec '"$SYSDIR\regsvr32.exe" /s "$INSTDIR\data\obs-plugins\win-dshow\obs-virtualcam-module32.dll"'
|
||||||
|
${if} ${RunningX64}
|
||||||
|
Exec '"$SYSDIR\regsvr32.exe" /s "$INSTDIR\data\obs-plugins\win-dshow\obs-virtualcam-module64.dll"'
|
||||||
|
${endif}
|
||||||
|
|
||||||
# ---------------------------------------
|
# ---------------------------------------
|
||||||
|
|
||||||
ClearErrors
|
ClearErrors
|
||||||
|
@ -420,6 +428,12 @@ Section "un.obs-studio Program Files" UninstallSection1
|
||||||
SetShellVarContext current
|
SetShellVarContext current
|
||||||
ClearErrors
|
ClearErrors
|
||||||
|
|
||||||
|
; Unregister virtual camera dlls
|
||||||
|
Exec '"$SYSDIR\regsvr32.exe" /u /s "$INSTDIR\data\obs-plugins\win-dshow\obs-virtualcam-module32.dll"'
|
||||||
|
${if} ${RunningX64}
|
||||||
|
Exec '"$SYSDIR\regsvr32.exe" /u /s "$INSTDIR\data\obs-plugins\win-dshow\obs-virtualcam-module64.dll"'
|
||||||
|
${endif}
|
||||||
|
|
||||||
; Remove from registry...
|
; Remove from registry...
|
||||||
DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APPNAME}"
|
DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APPNAME}"
|
||||||
DeleteRegKey HKLM "SOFTWARE\${APPNAME}"
|
DeleteRegKey HKLM "SOFTWARE\${APPNAME}"
|
||||||
|
|
|
@ -75,6 +75,7 @@ bool opt_start_streaming = false;
|
||||||
bool opt_start_recording = false;
|
bool opt_start_recording = false;
|
||||||
bool opt_studio_mode = false;
|
bool opt_studio_mode = false;
|
||||||
bool opt_start_replaybuffer = false;
|
bool opt_start_replaybuffer = false;
|
||||||
|
bool opt_start_virtualcam = false;
|
||||||
bool opt_minimize_tray = false;
|
bool opt_minimize_tray = false;
|
||||||
bool opt_allow_opengl = false;
|
bool opt_allow_opengl = false;
|
||||||
bool opt_always_on_top = false;
|
bool opt_always_on_top = false;
|
||||||
|
@ -2425,6 +2426,9 @@ int main(int argc, char *argv[])
|
||||||
} else if (arg_is(argv[i], "--startreplaybuffer", nullptr)) {
|
} else if (arg_is(argv[i], "--startreplaybuffer", nullptr)) {
|
||||||
opt_start_replaybuffer = true;
|
opt_start_replaybuffer = true;
|
||||||
|
|
||||||
|
} else if (arg_is(argv[i], "--startvirtualcam", nullptr)) {
|
||||||
|
opt_start_virtualcam = true;
|
||||||
|
|
||||||
} else if (arg_is(argv[i], "--collection", nullptr)) {
|
} else if (arg_is(argv[i], "--collection", nullptr)) {
|
||||||
if (++i < argc)
|
if (++i < argc)
|
||||||
opt_starting_collection = argv[i];
|
opt_starting_collection = argv[i];
|
||||||
|
@ -2451,7 +2455,8 @@ int main(int argc, char *argv[])
|
||||||
<< "--help, -h: Get list of available commands.\n\n"
|
<< "--help, -h: Get list of available commands.\n\n"
|
||||||
<< "--startstreaming: Automatically start streaming.\n"
|
<< "--startstreaming: Automatically start streaming.\n"
|
||||||
<< "--startrecording: Automatically start recording.\n"
|
<< "--startrecording: Automatically start recording.\n"
|
||||||
<< "--startreplaybuffer: Start replay buffer.\n\n"
|
<< "--startreplaybuffer: Start replay buffer.\n"
|
||||||
|
<< "--startvirtualcam: Start virtual camera (if available).\n\n"
|
||||||
<< "--collection <string>: Use specific scene collection."
|
<< "--collection <string>: Use specific scene collection."
|
||||||
<< "\n"
|
<< "\n"
|
||||||
<< "--profile <string>: Use specific profile.\n"
|
<< "--profile <string>: Use specific profile.\n"
|
||||||
|
|
|
@ -225,6 +225,7 @@ extern std::string remuxFilename;
|
||||||
extern bool opt_start_streaming;
|
extern bool opt_start_streaming;
|
||||||
extern bool opt_start_recording;
|
extern bool opt_start_recording;
|
||||||
extern bool opt_start_replaybuffer;
|
extern bool opt_start_replaybuffer;
|
||||||
|
extern bool opt_start_virtualcam;
|
||||||
extern bool opt_minimize_tray;
|
extern bool opt_minimize_tray;
|
||||||
extern bool opt_studio_mode;
|
extern bool opt_studio_mode;
|
||||||
extern bool opt_allow_opengl;
|
extern bool opt_allow_opengl;
|
||||||
|
|
|
@ -1424,6 +1424,40 @@ static bool Update(wchar_t *cmdLine)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------- *
|
||||||
|
* Install virtual camera */
|
||||||
|
|
||||||
|
if (!bIsPortable) {
|
||||||
|
wchar_t regsvr[MAX_PATH];
|
||||||
|
wchar_t src[MAX_PATH];
|
||||||
|
wchar_t tmp[MAX_PATH];
|
||||||
|
wchar_t tmp2[MAX_PATH];
|
||||||
|
|
||||||
|
SHGetFolderPathW(nullptr, CSIDL_SYSTEM, nullptr,
|
||||||
|
SHGFP_TYPE_CURRENT, regsvr);
|
||||||
|
StringCbCat(regsvr, sizeof(regsvr), L"\\regsvr32.exe");
|
||||||
|
|
||||||
|
GetCurrentDirectoryW(_countof(src), src);
|
||||||
|
StringCbCat(src, sizeof(src),
|
||||||
|
L"\\data\\obs-plugins\\win-dshow\\");
|
||||||
|
|
||||||
|
StringCbCopy(tmp, sizeof(tmp), L"\"\"");
|
||||||
|
StringCbCat(tmp, sizeof(tmp), regsvr);
|
||||||
|
StringCbCat(tmp, sizeof(tmp), L"\" /s \"");
|
||||||
|
StringCbCat(tmp, sizeof(tmp), src);
|
||||||
|
StringCbCat(tmp, sizeof(tmp), L"obs-virtualcam-module");
|
||||||
|
|
||||||
|
StringCbCopy(tmp2, sizeof(tmp2), tmp);
|
||||||
|
StringCbCat(tmp2, sizeof(tmp2), L"32.dll\"\"");
|
||||||
|
_wsystem(tmp2);
|
||||||
|
|
||||||
|
if (is_64bit_windows()) {
|
||||||
|
StringCbCopy(tmp2, sizeof(tmp2), tmp);
|
||||||
|
StringCbCat(tmp2, sizeof(tmp2), L"64.dll\"\"");
|
||||||
|
_wsystem(tmp2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* ------------------------------------- *
|
/* ------------------------------------- *
|
||||||
* Update hook files and vulkan registry */
|
* Update hook files and vulkan registry */
|
||||||
|
|
||||||
|
|
|
@ -990,7 +990,7 @@ void AutoConfigTestPage::FinalizeResults()
|
||||||
return new QLabel(QTStr(str), this);
|
return new QLabel(QTStr(str), this);
|
||||||
};
|
};
|
||||||
|
|
||||||
if (wiz->type != AutoConfig::Type::Recording) {
|
if (wiz->type == AutoConfig::Type::Streaming) {
|
||||||
const char *serverType = wiz->customServer ? "rtmp_custom"
|
const char *serverType = wiz->customServer ? "rtmp_custom"
|
||||||
: "rtmp_common";
|
: "rtmp_common";
|
||||||
|
|
||||||
|
@ -1093,7 +1093,7 @@ void AutoConfigTestPage::NextStage()
|
||||||
started = true;
|
started = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (wiz->type == AutoConfig::Type::Recording) {
|
if (wiz->type != AutoConfig::Type::Streaming) {
|
||||||
stage = Stage::StreamEncoder;
|
stage = Stage::StreamEncoder;
|
||||||
} else if (!wiz->bandwidthTest) {
|
} else if (!wiz->bandwidthTest) {
|
||||||
stage = Stage::BandwidthTest;
|
stage = Stage::BandwidthTest;
|
||||||
|
@ -1163,8 +1163,17 @@ AutoConfigTestPage::~AutoConfigTestPage()
|
||||||
|
|
||||||
void AutoConfigTestPage::initializePage()
|
void AutoConfigTestPage::initializePage()
|
||||||
{
|
{
|
||||||
|
if (wiz->type == AutoConfig::Type::VirtualCam) {
|
||||||
|
wiz->idealResolutionCX = wiz->baseResolutionCX;
|
||||||
|
wiz->idealResolutionCY = wiz->baseResolutionCY;
|
||||||
|
wiz->idealFPSNum = 30;
|
||||||
|
wiz->idealFPSDen = 1;
|
||||||
|
stage = Stage::Finished;
|
||||||
|
} else {
|
||||||
|
stage = Stage::Starting;
|
||||||
|
}
|
||||||
|
|
||||||
setSubTitle(QTStr(SUBTITLE_TESTING));
|
setSubTitle(QTStr(SUBTITLE_TESTING));
|
||||||
stage = Stage::Starting;
|
|
||||||
softwareTested = false;
|
softwareTested = false;
|
||||||
cancel = false;
|
cancel = false;
|
||||||
DeleteLayout(results);
|
DeleteLayout(results);
|
||||||
|
|
|
@ -69,6 +69,18 @@ AutoConfigStartPage::AutoConfigStartPage(QWidget *parent)
|
||||||
ui->setupUi(this);
|
ui->setupUi(this);
|
||||||
setTitle(QTStr("Basic.AutoConfig.StartPage"));
|
setTitle(QTStr("Basic.AutoConfig.StartPage"));
|
||||||
setSubTitle(QTStr("Basic.AutoConfig.StartPage.SubTitle"));
|
setSubTitle(QTStr("Basic.AutoConfig.StartPage.SubTitle"));
|
||||||
|
|
||||||
|
OBSBasic *main = OBSBasic::Get();
|
||||||
|
if (main->VCamEnabled()) {
|
||||||
|
QRadioButton *prioritizeVCam = new QRadioButton(
|
||||||
|
QTStr("Basic.AutoConfig.StartPage.PrioritizeVirtualCam"),
|
||||||
|
this);
|
||||||
|
QBoxLayout *box = reinterpret_cast<QBoxLayout *>(layout());
|
||||||
|
box->insertWidget(2, prioritizeVCam);
|
||||||
|
|
||||||
|
connect(prioritizeVCam, &QPushButton::clicked, this,
|
||||||
|
&AutoConfigStartPage::PrioritizeVCam);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AutoConfigStartPage::~AutoConfigStartPage()
|
AutoConfigStartPage::~AutoConfigStartPage()
|
||||||
|
@ -78,7 +90,9 @@ AutoConfigStartPage::~AutoConfigStartPage()
|
||||||
|
|
||||||
int AutoConfigStartPage::nextId() const
|
int AutoConfigStartPage::nextId() const
|
||||||
{
|
{
|
||||||
return AutoConfig::VideoPage;
|
return wiz->type == AutoConfig::Type::VirtualCam
|
||||||
|
? AutoConfig::TestPage
|
||||||
|
: AutoConfig::VideoPage;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AutoConfigStartPage::on_prioritizeStreaming_clicked()
|
void AutoConfigStartPage::on_prioritizeStreaming_clicked()
|
||||||
|
@ -91,6 +105,11 @@ void AutoConfigStartPage::on_prioritizeRecording_clicked()
|
||||||
wiz->type = AutoConfig::Type::Recording;
|
wiz->type = AutoConfig::Type::Recording;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AutoConfigStartPage::PrioritizeVCam()
|
||||||
|
{
|
||||||
|
wiz->type = AutoConfig::Type::VirtualCam;
|
||||||
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------------------- */
|
/* ------------------------------------------------------------------------- */
|
||||||
|
|
||||||
#define RES_TEXT(x) "Basic.AutoConfig.VideoPage." x
|
#define RES_TEXT(x) "Basic.AutoConfig.VideoPage." x
|
||||||
|
|
|
@ -33,6 +33,7 @@ class AutoConfig : public QWizard {
|
||||||
Invalid,
|
Invalid,
|
||||||
Streaming,
|
Streaming,
|
||||||
Recording,
|
Recording,
|
||||||
|
VirtualCam,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class Service {
|
enum class Service {
|
||||||
|
@ -139,6 +140,7 @@ public:
|
||||||
public slots:
|
public slots:
|
||||||
void on_prioritizeStreaming_clicked();
|
void on_prioritizeStreaming_clicked();
|
||||||
void on_prioritizeRecording_clicked();
|
void on_prioritizeRecording_clicked();
|
||||||
|
void PrioritizeVCam();
|
||||||
};
|
};
|
||||||
|
|
||||||
class AutoConfigVideoPage : public QWizardPage {
|
class AutoConfigVideoPage : public QWizardPage {
|
||||||
|
|
|
@ -14,6 +14,7 @@ volatile bool streaming_active = false;
|
||||||
volatile bool recording_active = false;
|
volatile bool recording_active = false;
|
||||||
volatile bool recording_paused = false;
|
volatile bool recording_paused = false;
|
||||||
volatile bool replaybuf_active = false;
|
volatile bool replaybuf_active = false;
|
||||||
|
volatile bool virtualcam_active = false;
|
||||||
|
|
||||||
#define RTMP_PROTOCOL "rtmp"
|
#define RTMP_PROTOCOL "rtmp"
|
||||||
|
|
||||||
|
@ -139,6 +140,30 @@ static void OBSReplayBufferStopping(void *data, calldata_t *params)
|
||||||
UNUSED_PARAMETER(params);
|
UNUSED_PARAMETER(params);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void OBSStartVirtualCam(void *data, calldata_t *params)
|
||||||
|
{
|
||||||
|
BasicOutputHandler *output = static_cast<BasicOutputHandler *>(data);
|
||||||
|
|
||||||
|
output->virtualCamActive = true;
|
||||||
|
os_atomic_set_bool(&virtualcam_active, true);
|
||||||
|
QMetaObject::invokeMethod(output->main, "OnVirtualCamStart");
|
||||||
|
|
||||||
|
UNUSED_PARAMETER(params);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void OBSStopVirtualCam(void *data, calldata_t *params)
|
||||||
|
{
|
||||||
|
BasicOutputHandler *output = static_cast<BasicOutputHandler *>(data);
|
||||||
|
int code = (int)calldata_int(params, "code");
|
||||||
|
|
||||||
|
output->virtualCamActive = false;
|
||||||
|
os_atomic_set_bool(&virtualcam_active, false);
|
||||||
|
QMetaObject::invokeMethod(output->main, "OnVirtualCamStop",
|
||||||
|
Q_ARG(int, code));
|
||||||
|
|
||||||
|
UNUSED_PARAMETER(params);
|
||||||
|
}
|
||||||
|
|
||||||
static void FindBestFilename(string &strPath, bool noSpace)
|
static void FindBestFilename(string &strPath, bool noSpace)
|
||||||
{
|
{
|
||||||
int num = 2;
|
int num = 2;
|
||||||
|
@ -197,6 +222,49 @@ static bool CreateAACEncoder(OBSEncoder &res, string &id, int bitrate,
|
||||||
|
|
||||||
/* ------------------------------------------------------------------------ */
|
/* ------------------------------------------------------------------------ */
|
||||||
|
|
||||||
|
inline BasicOutputHandler::BasicOutputHandler(OBSBasic *main_) : main(main_)
|
||||||
|
{
|
||||||
|
if (main->vcamEnabled) {
|
||||||
|
virtualCam = obs_output_create("virtualcam_output",
|
||||||
|
"virtualcam_output", nullptr,
|
||||||
|
nullptr);
|
||||||
|
obs_output_release(virtualCam);
|
||||||
|
|
||||||
|
signal_handler_t *signal =
|
||||||
|
obs_output_get_signal_handler(virtualCam);
|
||||||
|
startVirtualCam.Connect(signal, "start", OBSStartVirtualCam,
|
||||||
|
this);
|
||||||
|
stopVirtualCam.Connect(signal, "stop", OBSStopVirtualCam, this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BasicOutputHandler::StartVirtualCam()
|
||||||
|
{
|
||||||
|
if (main->vcamEnabled) {
|
||||||
|
obs_output_set_media(virtualCam, obs_get_video(),
|
||||||
|
obs_get_audio());
|
||||||
|
return obs_output_start(virtualCam);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BasicOutputHandler::StopVirtualCam()
|
||||||
|
{
|
||||||
|
if (main->vcamEnabled) {
|
||||||
|
obs_output_stop(virtualCam);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BasicOutputHandler::VirtualCamActive() const
|
||||||
|
{
|
||||||
|
if (main->vcamEnabled) {
|
||||||
|
return obs_output_active(virtualCam);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------------ */
|
||||||
|
|
||||||
struct SimpleOutput : BasicOutputHandler {
|
struct SimpleOutput : BasicOutputHandler {
|
||||||
OBSEncoder aacStreaming;
|
OBSEncoder aacStreaming;
|
||||||
OBSEncoder h264Streaming;
|
OBSEncoder h264Streaming;
|
||||||
|
|
|
@ -8,10 +8,12 @@ struct BasicOutputHandler {
|
||||||
OBSOutput fileOutput;
|
OBSOutput fileOutput;
|
||||||
OBSOutput streamOutput;
|
OBSOutput streamOutput;
|
||||||
OBSOutput replayBuffer;
|
OBSOutput replayBuffer;
|
||||||
|
OBSOutput virtualCam;
|
||||||
bool streamingActive = false;
|
bool streamingActive = false;
|
||||||
bool recordingActive = false;
|
bool recordingActive = false;
|
||||||
bool delayActive = false;
|
bool delayActive = false;
|
||||||
bool replayBufferActive = false;
|
bool replayBufferActive = false;
|
||||||
|
bool virtualCamActive = false;
|
||||||
OBSBasic *main;
|
OBSBasic *main;
|
||||||
|
|
||||||
std::string outputType;
|
std::string outputType;
|
||||||
|
@ -23,31 +25,36 @@ struct BasicOutputHandler {
|
||||||
OBSSignal stopReplayBuffer;
|
OBSSignal stopReplayBuffer;
|
||||||
OBSSignal startStreaming;
|
OBSSignal startStreaming;
|
||||||
OBSSignal stopStreaming;
|
OBSSignal stopStreaming;
|
||||||
|
OBSSignal startVirtualCam;
|
||||||
|
OBSSignal stopVirtualCam;
|
||||||
OBSSignal streamDelayStarting;
|
OBSSignal streamDelayStarting;
|
||||||
OBSSignal streamStopping;
|
OBSSignal streamStopping;
|
||||||
OBSSignal recordStopping;
|
OBSSignal recordStopping;
|
||||||
OBSSignal replayBufferStopping;
|
OBSSignal replayBufferStopping;
|
||||||
|
|
||||||
inline BasicOutputHandler(OBSBasic *main_) : main(main_) {}
|
inline BasicOutputHandler(OBSBasic *main_);
|
||||||
|
|
||||||
virtual ~BasicOutputHandler(){};
|
virtual ~BasicOutputHandler(){};
|
||||||
|
|
||||||
virtual bool StartStreaming(obs_service_t *service) = 0;
|
virtual bool StartStreaming(obs_service_t *service) = 0;
|
||||||
virtual bool StartRecording() = 0;
|
virtual bool StartRecording() = 0;
|
||||||
virtual bool StartReplayBuffer() { return false; }
|
virtual bool StartReplayBuffer() { return false; }
|
||||||
|
virtual bool StartVirtualCam();
|
||||||
virtual void StopStreaming(bool force = false) = 0;
|
virtual void StopStreaming(bool force = false) = 0;
|
||||||
virtual void StopRecording(bool force = false) = 0;
|
virtual void StopRecording(bool force = false) = 0;
|
||||||
virtual void StopReplayBuffer(bool force = false) { (void)force; }
|
virtual void StopReplayBuffer(bool force = false) { (void)force; }
|
||||||
|
virtual void StopVirtualCam();
|
||||||
virtual bool StreamingActive() const = 0;
|
virtual bool StreamingActive() const = 0;
|
||||||
virtual bool RecordingActive() const = 0;
|
virtual bool RecordingActive() const = 0;
|
||||||
virtual bool ReplayBufferActive() const { return false; }
|
virtual bool ReplayBufferActive() const { return false; }
|
||||||
|
virtual bool VirtualCamActive() const;
|
||||||
|
|
||||||
virtual void Update() = 0;
|
virtual void Update() = 0;
|
||||||
|
|
||||||
inline bool Active() const
|
inline bool Active() const
|
||||||
{
|
{
|
||||||
return streamingActive || recordingActive || delayActive ||
|
return streamingActive || recordingActive || delayActive ||
|
||||||
replayBufferActive;
|
replayBufferActive || virtualCamActive;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1080,6 +1080,12 @@ retryScene:
|
||||||
opt_start_replaybuffer = false;
|
opt_start_replaybuffer = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (opt_start_virtualcam) {
|
||||||
|
QMetaObject::invokeMethod(this, "StartVirtualCam",
|
||||||
|
Qt::QueuedConnection);
|
||||||
|
opt_start_virtualcam = false;
|
||||||
|
}
|
||||||
|
|
||||||
copyStrings.clear();
|
copyStrings.clear();
|
||||||
copyFiltersString = nullptr;
|
copyFiltersString = nullptr;
|
||||||
|
|
||||||
|
@ -1518,6 +1524,18 @@ void OBSBasic::ReplayBufferClicked()
|
||||||
StartReplayBuffer();
|
StartReplayBuffer();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void OBSBasic::AddVCamButton()
|
||||||
|
{
|
||||||
|
vcamButton = new ReplayBufferButton(QTStr("Basic.Main.StartVirtualCam"),
|
||||||
|
this);
|
||||||
|
vcamButton->setCheckable(true);
|
||||||
|
connect(vcamButton.data(), &QPushButton::clicked, this,
|
||||||
|
&OBSBasic::VCamButtonClicked);
|
||||||
|
|
||||||
|
vcamButton->setProperty("themeID", "vcamButton");
|
||||||
|
ui->buttonsVLayout->insertWidget(2, vcamButton);
|
||||||
|
}
|
||||||
|
|
||||||
void OBSBasic::ResetOutputs()
|
void OBSBasic::ResetOutputs()
|
||||||
{
|
{
|
||||||
ProfileScope("OBSBasic::ResetOutputs");
|
ProfileScope("OBSBasic::ResetOutputs");
|
||||||
|
@ -1645,6 +1663,13 @@ void OBSBasic::OBSInit()
|
||||||
cef = obs_browser_init_panel();
|
cef = obs_browser_init_panel();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
obs_data_t *obsData = obs_get_private_data();
|
||||||
|
vcamEnabled = obs_data_get_bool(obsData, "vcamEnabled");
|
||||||
|
if (vcamEnabled) {
|
||||||
|
AddVCamButton();
|
||||||
|
}
|
||||||
|
obs_data_release(obsData);
|
||||||
|
|
||||||
InitBasicConfigDefaults2();
|
InitBasicConfigDefaults2();
|
||||||
|
|
||||||
CheckForSimpleModeX264Fallback();
|
CheckForSimpleModeX264Fallback();
|
||||||
|
@ -2248,6 +2273,23 @@ void OBSBasic::CreateHotkeys()
|
||||||
LoadHotkeyPair(replayBufHotkeys, "OBSBasic.StartReplayBuffer",
|
LoadHotkeyPair(replayBufHotkeys, "OBSBasic.StartReplayBuffer",
|
||||||
"OBSBasic.StopReplayBuffer");
|
"OBSBasic.StopReplayBuffer");
|
||||||
|
|
||||||
|
if (vcamEnabled) {
|
||||||
|
vcamHotkeys = obs_hotkey_pair_register_frontend(
|
||||||
|
"OBSBasic.StartVirtualCam",
|
||||||
|
Str("Basic.Main.StartVirtualCam"),
|
||||||
|
"OBSBasic.StopVirtualCam",
|
||||||
|
Str("Basic.Main.StopVirtualCam"),
|
||||||
|
MAKE_CALLBACK(!basic.outputHandler->VirtualCamActive(),
|
||||||
|
basic.StartVirtualCam,
|
||||||
|
"Starting virtual camera"),
|
||||||
|
MAKE_CALLBACK(basic.outputHandler->VirtualCamActive(),
|
||||||
|
basic.StopVirtualCam,
|
||||||
|
"Stopping virtual camera"),
|
||||||
|
this, this);
|
||||||
|
LoadHotkeyPair(vcamHotkeys, "OBSBasic.StartVirtualCam",
|
||||||
|
"OBSBasic.StopVirtualCam");
|
||||||
|
}
|
||||||
|
|
||||||
togglePreviewHotkeys = obs_hotkey_pair_register_frontend(
|
togglePreviewHotkeys = obs_hotkey_pair_register_frontend(
|
||||||
"OBSBasic.EnablePreview",
|
"OBSBasic.EnablePreview",
|
||||||
Str("Basic.Main.PreviewConextMenu.Enable"),
|
Str("Basic.Main.PreviewConextMenu.Enable"),
|
||||||
|
@ -5247,6 +5289,10 @@ void OBSBasic::OpenSceneFilters()
|
||||||
"==== Streaming Start ==============================================="
|
"==== Streaming Start ==============================================="
|
||||||
#define STREAMING_STOP \
|
#define STREAMING_STOP \
|
||||||
"==== Streaming Stop ================================================"
|
"==== Streaming Stop ================================================"
|
||||||
|
#define VIRTUAL_CAM_START \
|
||||||
|
"==== Virtual Camera Start =========================================="
|
||||||
|
#define VIRTUAL_CAM_STOP \
|
||||||
|
"==== Virtual Camera Stop ==========================================="
|
||||||
|
|
||||||
void OBSBasic::StartStreaming()
|
void OBSBasic::StartStreaming()
|
||||||
{
|
{
|
||||||
|
@ -5967,6 +6013,61 @@ void OBSBasic::ReplayBufferStop(int code)
|
||||||
UpdateReplayBuffer(false);
|
UpdateReplayBuffer(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void OBSBasic::StartVirtualCam()
|
||||||
|
{
|
||||||
|
if (!outputHandler || !outputHandler->virtualCam)
|
||||||
|
return;
|
||||||
|
if (outputHandler->VirtualCamActive())
|
||||||
|
return;
|
||||||
|
if (disableOutputsRef)
|
||||||
|
return;
|
||||||
|
|
||||||
|
SaveProject();
|
||||||
|
|
||||||
|
if (!outputHandler->StartVirtualCam()) {
|
||||||
|
vcamButton->setChecked(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void OBSBasic::StopVirtualCam()
|
||||||
|
{
|
||||||
|
if (!outputHandler || !outputHandler->virtualCam)
|
||||||
|
return;
|
||||||
|
|
||||||
|
SaveProject();
|
||||||
|
|
||||||
|
if (outputHandler->VirtualCamActive())
|
||||||
|
outputHandler->StopVirtualCam();
|
||||||
|
|
||||||
|
OnDeactivate();
|
||||||
|
}
|
||||||
|
|
||||||
|
void OBSBasic::OnVirtualCamStart()
|
||||||
|
{
|
||||||
|
if (!outputHandler || !outputHandler->virtualCam)
|
||||||
|
return;
|
||||||
|
|
||||||
|
vcamButton->setText(QTStr("Basic.Main.StopVirtualCam"));
|
||||||
|
vcamButton->setChecked(true);
|
||||||
|
|
||||||
|
OnActivate();
|
||||||
|
|
||||||
|
blog(LOG_INFO, VIRTUAL_CAM_START);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OBSBasic::OnVirtualCamStop(int)
|
||||||
|
{
|
||||||
|
if (!outputHandler || !outputHandler->virtualCam)
|
||||||
|
return;
|
||||||
|
|
||||||
|
vcamButton->setText(QTStr("Basic.Main.StartVirtualCam"));
|
||||||
|
vcamButton->setChecked(false);
|
||||||
|
|
||||||
|
blog(LOG_INFO, VIRTUAL_CAM_STOP);
|
||||||
|
|
||||||
|
OnDeactivate();
|
||||||
|
}
|
||||||
|
|
||||||
void OBSBasic::on_streamButton_clicked()
|
void OBSBasic::on_streamButton_clicked()
|
||||||
{
|
{
|
||||||
if (outputHandler->StreamingActive()) {
|
if (outputHandler->StreamingActive()) {
|
||||||
|
@ -6073,6 +6174,20 @@ void OBSBasic::on_recordButton_clicked()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void OBSBasic::VCamButtonClicked()
|
||||||
|
{
|
||||||
|
if (outputHandler->VirtualCamActive()) {
|
||||||
|
StopVirtualCam();
|
||||||
|
} else {
|
||||||
|
if (!UIValidation::NoSourcesConfirmation(this)) {
|
||||||
|
vcamButton->setChecked(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
StartVirtualCam();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void OBSBasic::on_settingsButton_clicked()
|
void OBSBasic::on_settingsButton_clicked()
|
||||||
{
|
{
|
||||||
on_action_Settings_triggered();
|
on_action_Settings_triggered();
|
||||||
|
|
|
@ -166,6 +166,7 @@ class OBSBasic : public OBSMainWindow {
|
||||||
friend class ReplayBufferButton;
|
friend class ReplayBufferButton;
|
||||||
friend class ExtraBrowsersModel;
|
friend class ExtraBrowsersModel;
|
||||||
friend class ExtraBrowsersDelegate;
|
friend class ExtraBrowsersDelegate;
|
||||||
|
friend struct BasicOutputHandler;
|
||||||
friend struct OBSStudioAPI;
|
friend struct OBSStudioAPI;
|
||||||
|
|
||||||
enum class MoveDir { Up, Down, Left, Right };
|
enum class MoveDir { Up, Down, Left, Right };
|
||||||
|
@ -256,6 +257,9 @@ private:
|
||||||
QScopedPointer<QPushButton> pause;
|
QScopedPointer<QPushButton> pause;
|
||||||
QScopedPointer<QPushButton> replay;
|
QScopedPointer<QPushButton> replay;
|
||||||
|
|
||||||
|
QPointer<QPushButton> vcamButton;
|
||||||
|
bool vcamEnabled = false;
|
||||||
|
|
||||||
QScopedPointer<QSystemTrayIcon> trayIcon;
|
QScopedPointer<QSystemTrayIcon> trayIcon;
|
||||||
QPointer<QAction> sysTrayStream;
|
QPointer<QAction> sysTrayStream;
|
||||||
QPointer<QAction> sysTrayRecord;
|
QPointer<QAction> sysTrayRecord;
|
||||||
|
@ -382,7 +386,7 @@ private:
|
||||||
QModelIndexList GetAllSelectedSourceItems();
|
QModelIndexList GetAllSelectedSourceItems();
|
||||||
|
|
||||||
obs_hotkey_pair_id streamingHotkeys, recordingHotkeys, pauseHotkeys,
|
obs_hotkey_pair_id streamingHotkeys, recordingHotkeys, pauseHotkeys,
|
||||||
replayBufHotkeys, togglePreviewHotkeys;
|
replayBufHotkeys, vcamHotkeys, togglePreviewHotkeys;
|
||||||
obs_hotkey_id forceStreamingStopHotkey;
|
obs_hotkey_id forceStreamingStopHotkey;
|
||||||
|
|
||||||
void InitDefaultTransitions();
|
void InitDefaultTransitions();
|
||||||
|
@ -561,6 +565,12 @@ public slots:
|
||||||
void ReplayBufferStopping();
|
void ReplayBufferStopping();
|
||||||
void ReplayBufferStop(int code);
|
void ReplayBufferStop(int code);
|
||||||
|
|
||||||
|
void StartVirtualCam();
|
||||||
|
void StopVirtualCam();
|
||||||
|
|
||||||
|
void OnVirtualCamStart();
|
||||||
|
void OnVirtualCamStop(int code);
|
||||||
|
|
||||||
void SaveProjectDeferred();
|
void SaveProjectDeferred();
|
||||||
void SaveProject();
|
void SaveProject();
|
||||||
|
|
||||||
|
@ -740,6 +750,8 @@ public:
|
||||||
return os_atomic_load_bool(&previewProgramMode);
|
return os_atomic_load_bool(&previewProgramMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline bool VCamEnabled() const { return vcamEnabled; }
|
||||||
|
|
||||||
bool StreamingActive() const;
|
bool StreamingActive() const;
|
||||||
bool Active() const;
|
bool Active() const;
|
||||||
|
|
||||||
|
@ -747,6 +759,7 @@ public:
|
||||||
int ResetVideo();
|
int ResetVideo();
|
||||||
bool ResetAudio();
|
bool ResetAudio();
|
||||||
|
|
||||||
|
void AddVCamButton();
|
||||||
void ResetOutputs();
|
void ResetOutputs();
|
||||||
|
|
||||||
void ResetAudioDevice(const char *sourceId, const char *deviceId,
|
void ResetAudioDevice(const char *sourceId, const char *deviceId,
|
||||||
|
@ -887,6 +900,7 @@ private slots:
|
||||||
|
|
||||||
void on_streamButton_clicked();
|
void on_streamButton_clicked();
|
||||||
void on_recordButton_clicked();
|
void on_recordButton_clicked();
|
||||||
|
void VCamButtonClicked();
|
||||||
void on_settingsButton_clicked();
|
void on_settingsButton_clicked();
|
||||||
|
|
||||||
void on_actionHelpPortal_triggered();
|
void on_actionHelpPortal_triggered();
|
||||||
|
|
Loading…
Reference in New Issue