Skip to content

Commit

Permalink
UI: Remove QFuture usage
Browse files Browse the repository at this point in the history
`QFuture`s are broken on older Qt versions, even with the deadlock
workaround (see <#10929>)
  • Loading branch information
palana authored and RytoEX committed Jul 10, 2024
1 parent b74e7ed commit 7327663
Show file tree
Hide file tree
Showing 10 changed files with 105 additions and 135 deletions.
2 changes: 0 additions & 2 deletions UI/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -98,8 +98,6 @@ target_sources(
multitrack-video-error.hpp
multitrack-video-output.cpp
multitrack-video-output.hpp
qt-helpers.cpp
qt-helpers.hpp
system-info.hpp)

if(OS_WINDOWS)
Expand Down
1 change: 0 additions & 1 deletion UI/goliveapi-network.hpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
#pragma once

#include <obs.hpp>
#include <QFuture>
#include <QString>

#include "models/multitrack-video.hpp"
Expand Down
1 change: 0 additions & 1 deletion UI/multitrack-video-output.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@
#include "goliveapi-postdata.hpp"
#include "goliveapi-network.hpp"
#include "multitrack-video-error.hpp"
#include "qt-helpers.hpp"
#include "models/multitrack-video.hpp"

Qt::ConnectionType BlockingConnectionTypeFor(QObject *object)
Expand Down
5 changes: 2 additions & 3 deletions UI/multitrack-video-output.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,11 @@
#include <util/config-file.h>

#include <atomic>
#include <mutex>
#include <optional>
#include <vector>

#include <qobject.h>
#include <QFuture>
#include <QFutureSynchronizer>
#include <QObject>

#define NOMINMAX

Expand Down
10 changes: 0 additions & 10 deletions UI/qt-helpers.cpp

This file was deleted.

46 changes: 0 additions & 46 deletions UI/qt-helpers.hpp

This file was deleted.

129 changes: 82 additions & 47 deletions UI/window-basic-main-outputs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
#include <algorithm>
#include <cinttypes>
#include <QMessageBox>
#include <QPromise>
#include <QThreadPool>
#include "qt-wrappers.hpp"
#include "audio-encoders.hpp"
#include "multitrack-video-error.hpp"
Expand Down Expand Up @@ -183,6 +183,28 @@ static void OBSDeactivateVirtualCam(void *data, calldata_t * /* params */)

/* ------------------------------------------------------------------------ */

struct StartMultitrackVideoStreamingGuard {
StartMultitrackVideoStreamingGuard()
{
future = guard.get_future().share();
};
~StartMultitrackVideoStreamingGuard() { guard.set_value(); }

std::shared_future<void> GetFuture() const { return future; }

static std::shared_future<void> MakeReadyFuture()
{
StartMultitrackVideoStreamingGuard guard;
return guard.GetFuture();
}

private:
std::promise<void> guard;
std::shared_future<void> future;
};

/* ------------------------------------------------------------------------ */

static bool CreateSimpleAACEncoder(OBSEncoder &res, int bitrate,
const char *name, size_t idx)
{
Expand Down Expand Up @@ -520,8 +542,9 @@ struct SimpleOutput : BasicOutputHandler {
bool IsVodTrackEnabled(obs_service_t *service);
void SetupVodTrack(obs_service_t *service);

virtual FutureHolder<bool>
SetupStreaming(obs_service_t *service) override;
virtual std::shared_future<void>
SetupStreaming(obs_service_t *service,
SetupStreamingContinuation_t continuation) override;
virtual bool StartStreaming(obs_service_t *service) override;
virtual bool StartRecording() override;
virtual bool StartReplayBuffer() override;
Expand Down Expand Up @@ -1118,7 +1141,9 @@ const char *FindAudioEncoderFromCodec(const char *type)
return nullptr;
}

FutureHolder<bool> SimpleOutput::SetupStreaming(obs_service_t *service)
std::shared_future<void>
SimpleOutput::SetupStreaming(obs_service_t *service,
SetupStreamingContinuation_t continuation)
{
if (!Active())
SetupOutputs();
Expand All @@ -1130,8 +1155,10 @@ FutureHolder<bool> SimpleOutput::SetupStreaming(obs_service_t *service)
/* --------------------- */

const char *type = GetStreamOutputType(service);
if (!type)
return {[] {}, CreateFuture().then([] { return false; })};
if (!type) {
continuation(false);
return StartMultitrackVideoStreamingGuard::MakeReadyFuture();
}

auto audio_bitrate = GetAudioBitrate();
auto vod_track_mixer = IsVodTrackEnabled(service) ? std::optional{1}
Expand Down Expand Up @@ -1182,12 +1209,11 @@ FutureHolder<bool> SimpleOutput::SetupStreaming(obs_service_t *service)
return true;
};

auto holder = SetupMultitrackVideo(
return SetupMultitrackVideo(
service, GetSimpleAACEncoderForBitrate(audio_bitrate), 0,
vod_track_mixer);
auto future = PreventFutureDeadlock(holder.future)
.then(main, handle_multitrack_video_result);
return {holder.cancelAll, future};
vod_track_mixer, [&, continuation](std::optional<bool> res) {
continuation(handle_multitrack_video_result(res));
});
}

static inline bool ServiceSupportsVodTrack(const char *service);
Expand Down Expand Up @@ -1567,8 +1593,9 @@ struct AdvancedOutput : BasicOutputHandler {
void SetupOutputs() override;
int GetAudioBitrate(size_t i, const char *id) const;

virtual FutureHolder<bool>
SetupStreaming(obs_service_t *service) override;
virtual std::shared_future<void>
SetupStreaming(obs_service_t *service,
SetupStreamingContinuation_t continuation) override;
virtual bool StartStreaming(obs_service_t *service) override;
virtual bool StartRecording() override;
virtual bool StartReplayBuffer() override;
Expand Down Expand Up @@ -2247,7 +2274,9 @@ inline void AdvancedOutput::SetupVodTrack(obs_service_t *service)
clear_archive_encoder(streamOutput, ADV_ARCHIVE_NAME);
}

FutureHolder<bool> AdvancedOutput::SetupStreaming(obs_service_t *service)
std::shared_future<void>
AdvancedOutput::SetupStreaming(obs_service_t *service,
SetupStreamingContinuation_t continuation)
{
int multiTrackAudioMixes = config_get_int(main->Config(), "AdvOut",
"StreamMultiTrackAudioMixes");
Expand All @@ -2272,8 +2301,10 @@ FutureHolder<bool> AdvancedOutput::SetupStreaming(obs_service_t *service)
/* --------------------- */

const char *type = GetStreamOutputType(service);
if (!type)
return {[] {}, CreateFuture().then(main, [] { return false; })};
if (!type) {
continuation(false);
return StartMultitrackVideoStreamingGuard::MakeReadyFuture();
}

const char *audio_encoder_id =
config_get_string(main->Config(), "AdvOut", "AudioEncoder");
Expand Down Expand Up @@ -2339,13 +2370,13 @@ FutureHolder<bool> AdvancedOutput::SetupStreaming(obs_service_t *service)
return true;
};

auto holder =
SetupMultitrackVideo(service, audio_encoder_id,
static_cast<size_t>(streamTrackIndex),
VodTrackMixerIdx(service));
auto future = PreventFutureDeadlock(holder.future)
.then(main, handle_multitrack_video_result);
return {holder.cancelAll, future};
return SetupMultitrackVideo(
service, audio_encoder_id,
static_cast<size_t>(streamTrackIndex),
VodTrackMixerIdx(service),
[&, continuation](std::optional<bool> res) {
continuation(handle_multitrack_video_result(res));
});
}

bool AdvancedOutput::StartStreaming(obs_service_t *service)
Expand Down Expand Up @@ -2683,14 +2714,17 @@ std::string BasicOutputHandler::GetRecordingFilename(

extern std::string DeserializeConfigText(const char *text);

FutureHolder<std::optional<bool>> BasicOutputHandler::SetupMultitrackVideo(
std::shared_future<void> BasicOutputHandler::SetupMultitrackVideo(
obs_service_t *service, std::string audio_encoder_id,
size_t main_audio_mixer, std::optional<size_t> vod_track_mixer)
size_t main_audio_mixer, std::optional<size_t> vod_track_mixer,
std::function<void(std::optional<bool>)> continuation)
{
if (!multitrackVideo)
return {[] {}, CreateFuture().then([] {
return std::optional<bool>{std::nullopt};
})};
auto start_streaming_guard =
std::make_shared<StartMultitrackVideoStreamingGuard>();
if (!multitrackVideo) {
continuation(std::nullopt);
return start_streaming_guard->GetFuture();
}

multitrackVideoActive = false;

Expand Down Expand Up @@ -2751,10 +2785,11 @@ FutureHolder<std::optional<bool>> BasicOutputHandler::SetupMultitrackVideo(

auto stream_dump_config = GenerateMultitrackVideoStreamDumpConfig();

auto continue_on_main_thread =
[&, service = OBSService{service}](
std::optional<MultitrackVideoError> error)
-> std::optional<bool> {
auto continue_on_main_thread = [&, start_streaming_guard,
service = OBSService{service},
continuation = std::move(continuation)](
std::optional<MultitrackVideoError>
error) {
if (error) {
OBSDataAutoRelease service_settings =
obs_service_get_settings(service);
Expand All @@ -2769,8 +2804,8 @@ FutureHolder<std::optional<bool>> BasicOutputHandler::SetupMultitrackVideo(

multitrackVideoActive = false;
if (!error->ShowDialog(main, multitrack_video_name))
return false;
return std::nullopt;
return continuation(false);
return continuation(std::nullopt);
}

multitrackVideoActive = true;
Expand All @@ -2786,16 +2821,16 @@ FutureHolder<std::optional<bool>> BasicOutputHandler::SetupMultitrackVideo(
OBSStartStreaming, this);
stopStreaming.Connect(signal_handler, "stop", OBSStopStreaming,
this);
return true;
return continuation(true);
};

auto firstFuture = CreateFuture().then(
QThreadPool::globalInstance(),
QThreadPool::globalInstance()->start(
[=, multitrackVideo = multitrackVideo.get(),
service_name = std::string{service_name},
service = OBSService{service},
stream_dump_config = std::move(stream_dump_config)]()
-> std::optional<MultitrackVideoError> {
stream_dump_config = OBSData{stream_dump_config},
start_streaming_guard = start_streaming_guard]() mutable {
std::optional<MultitrackVideoError> error;
try {
multitrackVideo->PrepareStreaming(
main, service_name.c_str(), service,
Expand All @@ -2805,16 +2840,16 @@ FutureHolder<std::optional<bool>> BasicOutputHandler::SetupMultitrackVideo(
maximum_video_tracks, custom_config,
stream_dump_config, main_audio_mixer,
vod_track_mixer);
} catch (const MultitrackVideoError &error) {
return error;
} catch (const MultitrackVideoError &error_) {
error.emplace(error_);
}
return std::nullopt;
});

auto secondFuture = firstFuture.then(main, continue_on_main_thread);
QMetaObject::invokeMethod(main, [=] {
continue_on_main_thread(error);
});
});

return {[=]() mutable { firstFuture.cancel(); },
PreventFutureDeadlock(secondFuture)};
return start_streaming_guard->GetFuture();
}

OBSDataAutoRelease BasicOutputHandler::GenerateMultitrackVideoStreamDumpConfig()
Expand Down
15 changes: 9 additions & 6 deletions UI/window-basic-main-outputs.hpp
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
#pragma once

#include <future>
#include <memory>
#include <string>

#include <QFuture>

#include "qt-helpers.hpp"
#include "multitrack-video-output.hpp"

class OBSBasic;

using SetupStreamingContinuation_t = std::function<void(bool)>;

struct BasicOutputHandler {
OBSOutputAutoRelease fileOutput;
OBSOutputAutoRelease streamOutput;
Expand Down Expand Up @@ -63,7 +63,9 @@ struct BasicOutputHandler {

virtual ~BasicOutputHandler(){};

virtual FutureHolder<bool> SetupStreaming(obs_service_t *service) = 0;
virtual std::shared_future<void>
SetupStreaming(obs_service_t *service,
SetupStreamingContinuation_t continuation) = 0;
virtual bool StartStreaming(obs_service_t *service) = 0;
virtual bool StartRecording() = 0;
virtual bool StartReplayBuffer() { return false; }
Expand Down Expand Up @@ -98,9 +100,10 @@ struct BasicOutputHandler {
bool overwrite, const char *format,
bool ffmpeg);

FutureHolder<std::optional<bool>> SetupMultitrackVideo(
std::shared_future<void> SetupMultitrackVideo(
obs_service_t *service, std::string audio_encoder_id,
size_t main_audio_mixer, std::optional<size_t> vod_track_mixer);
size_t main_audio_mixer, std::optional<size_t> vod_track_mixer,
std::function<void(std::optional<bool>)> continuation);
OBSDataAutoRelease GenerateMultitrackVideoStreamDumpConfig();
};

Expand Down
Loading

0 comments on commit 7327663

Please sign in to comment.