New upstream version 24.0.1+dfsg1
This commit is contained in:
parent
b14f9eae6d
commit
5a730d6ec3
842 changed files with 42245 additions and 33385 deletions
|
|
@ -17,7 +17,7 @@
|
|||
|
||||
using namespace std;
|
||||
|
||||
static Display* xdisplay = 0;
|
||||
static Display *xdisplay = 0;
|
||||
|
||||
Display *disp()
|
||||
{
|
||||
|
|
@ -39,31 +39,22 @@ void cleanupDisplay()
|
|||
static bool ewmhIsSupported()
|
||||
{
|
||||
Display *display = disp();
|
||||
Atom netSupportingWmCheck = XInternAtom(display,
|
||||
"_NET_SUPPORTING_WM_CHECK", true);
|
||||
Atom netSupportingWmCheck =
|
||||
XInternAtom(display, "_NET_SUPPORTING_WM_CHECK", true);
|
||||
Atom actualType;
|
||||
int format = 0;
|
||||
unsigned long num = 0, bytes = 0;
|
||||
unsigned char *data = NULL;
|
||||
Window ewmh_window = 0;
|
||||
|
||||
int status = XGetWindowProperty(
|
||||
display,
|
||||
DefaultRootWindow(display),
|
||||
netSupportingWmCheck,
|
||||
0L,
|
||||
1L,
|
||||
false,
|
||||
XA_WINDOW,
|
||||
&actualType,
|
||||
&format,
|
||||
&num,
|
||||
&bytes,
|
||||
&data);
|
||||
int status = XGetWindowProperty(display, DefaultRootWindow(display),
|
||||
netSupportingWmCheck, 0L, 1L, false,
|
||||
XA_WINDOW, &actualType, &format, &num,
|
||||
&bytes, &data);
|
||||
|
||||
if (status == Success) {
|
||||
if (num > 0) {
|
||||
ewmh_window = ((Window*)data)[0];
|
||||
ewmh_window = ((Window *)data)[0];
|
||||
}
|
||||
if (data) {
|
||||
XFree(data);
|
||||
|
|
@ -72,21 +63,12 @@ static bool ewmhIsSupported()
|
|||
}
|
||||
|
||||
if (ewmh_window) {
|
||||
status = XGetWindowProperty(
|
||||
display,
|
||||
ewmh_window,
|
||||
netSupportingWmCheck,
|
||||
0L,
|
||||
1L,
|
||||
false,
|
||||
XA_WINDOW,
|
||||
&actualType,
|
||||
&format,
|
||||
&num,
|
||||
&bytes,
|
||||
&data);
|
||||
status = XGetWindowProperty(display, ewmh_window,
|
||||
netSupportingWmCheck, 0L, 1L, false,
|
||||
XA_WINDOW, &actualType, &format,
|
||||
&num, &bytes, &data);
|
||||
if (status != Success || num == 0 ||
|
||||
ewmh_window != ((Window*)data)[0]) {
|
||||
ewmh_window != ((Window *)data)[0]) {
|
||||
ewmh_window = 0;
|
||||
}
|
||||
if (status == Success && data) {
|
||||
|
|
@ -111,24 +93,15 @@ static std::vector<Window> getTopLevelWindows()
|
|||
Atom actualType;
|
||||
int format;
|
||||
unsigned long num, bytes;
|
||||
Window* data = 0;
|
||||
Window *data = 0;
|
||||
|
||||
for (int i = 0; i < ScreenCount(disp()); ++i) {
|
||||
Window rootWin = RootWindow(disp(), i);
|
||||
|
||||
int status = XGetWindowProperty(
|
||||
disp(),
|
||||
rootWin,
|
||||
netClList,
|
||||
0L,
|
||||
~0L,
|
||||
false,
|
||||
AnyPropertyType,
|
||||
&actualType,
|
||||
&format,
|
||||
&num,
|
||||
&bytes,
|
||||
(uint8_t**)&data);
|
||||
int status = XGetWindowProperty(disp(), rootWin, netClList, 0L,
|
||||
~0L, false, AnyPropertyType,
|
||||
&actualType, &format, &num,
|
||||
&bytes, (uint8_t **)&data);
|
||||
|
||||
if (status != Success) {
|
||||
continue;
|
||||
|
|
@ -147,11 +120,10 @@ static std::string GetWindowTitle(size_t i)
|
|||
{
|
||||
Window w = getTopLevelWindows().at(i);
|
||||
std::string windowTitle;
|
||||
char* name;
|
||||
char *name;
|
||||
|
||||
int status = XFetchName(disp(), w, &name);
|
||||
if (status >= Success && name != nullptr)
|
||||
{
|
||||
if (status >= Success && name != nullptr) {
|
||||
std::string str(name);
|
||||
windowTitle = str;
|
||||
}
|
||||
|
|
@ -165,7 +137,7 @@ void GetWindowList(vector<string> &windows)
|
|||
{
|
||||
windows.resize(0);
|
||||
|
||||
for (size_t i = 0; i < getTopLevelWindows().size(); ++i){
|
||||
for (size_t i = 0; i < getTopLevelWindows().size(); ++i) {
|
||||
if (GetWindowTitle(i) != "")
|
||||
windows.emplace_back(GetWindowTitle(i));
|
||||
}
|
||||
|
|
@ -181,24 +153,14 @@ void GetCurrentWindowTitle(string &title)
|
|||
Atom actualType;
|
||||
int format;
|
||||
unsigned long num, bytes;
|
||||
Window* data = 0;
|
||||
char* name;
|
||||
Window *data = 0;
|
||||
char *name;
|
||||
|
||||
Window rootWin = RootWindow(disp(), 0);
|
||||
|
||||
XGetWindowProperty(
|
||||
disp(),
|
||||
rootWin,
|
||||
active,
|
||||
0L,
|
||||
~0L,
|
||||
false,
|
||||
AnyPropertyType,
|
||||
&actualType,
|
||||
&format,
|
||||
&num,
|
||||
&bytes,
|
||||
(uint8_t**)&data);
|
||||
XGetWindowProperty(disp(), rootWin, active, 0L, ~0L, false,
|
||||
AnyPropertyType, &actualType, &format, &num, &bytes,
|
||||
(uint8_t **)&data);
|
||||
|
||||
int status = XFetchName(disp(), data[0], &name);
|
||||
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ static bool WindowValid(HWND window)
|
|||
return false;
|
||||
|
||||
GetClientRect(window, &rect);
|
||||
styles = GetWindowLongPtr(window, GWL_STYLE);
|
||||
styles = GetWindowLongPtr(window, GWL_STYLE);
|
||||
ex_styles = GetWindowLongPtr(window, GWL_EXSTYLE);
|
||||
|
||||
if (ex_styles & WS_EX_TOOLWINDOW)
|
||||
|
|
|
|||
|
|
@ -69,23 +69,19 @@ struct SwitcherData {
|
|||
}
|
||||
}
|
||||
|
||||
inline ~SwitcherData()
|
||||
{
|
||||
Stop();
|
||||
}
|
||||
inline ~SwitcherData() { Stop(); }
|
||||
};
|
||||
|
||||
static SwitcherData *switcher = nullptr;
|
||||
|
||||
static inline QString MakeSwitchName(const QString &scene,
|
||||
const QString &window)
|
||||
const QString &window)
|
||||
{
|
||||
return QStringLiteral("[") + scene + QStringLiteral("]: ") + window;
|
||||
}
|
||||
|
||||
SceneSwitcher::SceneSwitcher(QWidget *parent)
|
||||
: QDialog(parent),
|
||||
ui(new Ui_SceneSwitcher)
|
||||
: QDialog(parent), ui(new Ui_SceneSwitcher)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
|
|
@ -95,7 +91,7 @@ SceneSwitcher::SceneSwitcher(QWidget *parent)
|
|||
|
||||
switcher->Prune();
|
||||
|
||||
BPtr<char*> scenes = obs_frontend_get_scene_names();
|
||||
BPtr<char *> scenes = obs_frontend_get_scene_names();
|
||||
char **temp = scenes;
|
||||
while (*temp) {
|
||||
const char *name = *temp;
|
||||
|
|
@ -110,7 +106,7 @@ SceneSwitcher::SceneSwitcher(QWidget *parent)
|
|||
ui->noMatchDontSwitch->setChecked(true);
|
||||
|
||||
ui->noMatchSwitchScene->setCurrentText(
|
||||
GetWeakSourceName(switcher->nonMatchingScene).c_str());
|
||||
GetWeakSourceName(switcher->nonMatchingScene).c_str());
|
||||
ui->checkInterval->setValue(switcher->interval);
|
||||
|
||||
vector<string> windows;
|
||||
|
|
@ -121,11 +117,10 @@ SceneSwitcher::SceneSwitcher(QWidget *parent)
|
|||
|
||||
for (auto &s : switcher->switches) {
|
||||
string sceneName = GetWeakSourceName(s.scene);
|
||||
QString text = MakeSwitchName(sceneName.c_str(),
|
||||
s.window.c_str());
|
||||
QString text =
|
||||
MakeSwitchName(sceneName.c_str(), s.window.c_str());
|
||||
|
||||
QListWidgetItem *item = new QListWidgetItem(text,
|
||||
ui->switches);
|
||||
QListWidgetItem *item = new QListWidgetItem(text, ui->switches);
|
||||
item->setData(Qt::UserRole, s.window.c_str());
|
||||
}
|
||||
|
||||
|
|
@ -137,7 +132,7 @@ SceneSwitcher::SceneSwitcher(QWidget *parent)
|
|||
loading = false;
|
||||
}
|
||||
|
||||
void SceneSwitcher::closeEvent(QCloseEvent*)
|
||||
void SceneSwitcher::closeEvent(QCloseEvent *)
|
||||
{
|
||||
obs_frontend_save();
|
||||
}
|
||||
|
|
@ -149,8 +144,7 @@ int SceneSwitcher::FindByData(const QString &window)
|
|||
|
||||
for (int i = 0; i < count; i++) {
|
||||
QListWidgetItem *item = ui->switches->item(i);
|
||||
QString itemWindow =
|
||||
item->data(Qt::UserRole).toString();
|
||||
QString itemWindow = item->data(Qt::UserRole).toString();
|
||||
|
||||
if (itemWindow == window) {
|
||||
idx = i;
|
||||
|
|
@ -206,16 +200,16 @@ void SceneSwitcher::on_add_clicked()
|
|||
if (idx == -1) {
|
||||
try {
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
switcher->switches.emplace_back(source,
|
||||
windowName.toUtf8().constData());
|
||||
|
||||
QListWidgetItem *item = new QListWidgetItem(text,
|
||||
ui->switches);
|
||||
switcher->switches.emplace_back(
|
||||
source, windowName.toUtf8().constData());
|
||||
|
||||
QListWidgetItem *item =
|
||||
new QListWidgetItem(text, ui->switches);
|
||||
item->setData(Qt::UserRole, v);
|
||||
} catch (const regex_error &) {
|
||||
QMessageBox::warning(this,
|
||||
obs_module_text("InvalidRegex.Title"),
|
||||
obs_module_text("InvalidRegex.Text"));
|
||||
QMessageBox::warning(
|
||||
this, obs_module_text("InvalidRegex.Title"),
|
||||
obs_module_text("InvalidRegex.Text"));
|
||||
}
|
||||
} else {
|
||||
QListWidgetItem *item = ui->switches->item(idx);
|
||||
|
|
@ -274,8 +268,7 @@ void SceneSwitcher::on_startAtLaunch_toggled(bool value)
|
|||
|
||||
void SceneSwitcher::UpdateNonMatchingScene(const QString &name)
|
||||
{
|
||||
obs_source_t *scene = obs_get_source_by_name(
|
||||
name.toUtf8().constData());
|
||||
obs_source_t *scene = obs_get_source_by_name(name.toUtf8().constData());
|
||||
obs_weak_source_t *ws = obs_source_get_weak_source(scene);
|
||||
|
||||
switcher->nonMatchingScene = ws;
|
||||
|
|
@ -303,8 +296,7 @@ void SceneSwitcher::on_noMatchSwitch_clicked()
|
|||
UpdateNonMatchingScene(ui->noMatchSwitchScene->currentText());
|
||||
}
|
||||
|
||||
void SceneSwitcher::on_noMatchSwitchScene_currentTextChanged(
|
||||
const QString &text)
|
||||
void SceneSwitcher::on_noMatchSwitchScene_currentTextChanged(const QString &text)
|
||||
{
|
||||
if (loading)
|
||||
return;
|
||||
|
|
@ -357,13 +349,13 @@ static void SaveSceneSwitcher(obs_data_t *save_data, bool saving, void *)
|
|||
for (SceneSwitch &s : switcher->switches) {
|
||||
obs_data_t *array_obj = obs_data_create();
|
||||
|
||||
obs_source_t *source = obs_weak_source_get_source(
|
||||
s.scene);
|
||||
obs_source_t *source =
|
||||
obs_weak_source_get_source(s.scene);
|
||||
if (source) {
|
||||
const char *n = obs_source_get_name(source);
|
||||
obs_data_set_string(array_obj, "scene", n);
|
||||
obs_data_set_string(array_obj, "window_title",
|
||||
s.window.c_str());
|
||||
s.window.c_str());
|
||||
obs_data_array_push_back(array, array_obj);
|
||||
obs_source_release(source);
|
||||
}
|
||||
|
|
@ -376,9 +368,9 @@ static void SaveSceneSwitcher(obs_data_t *save_data, bool saving, void *)
|
|||
|
||||
obs_data_set_int(obj, "interval", switcher->interval);
|
||||
obs_data_set_string(obj, "non_matching_scene",
|
||||
nonMatchingSceneName.c_str());
|
||||
nonMatchingSceneName.c_str());
|
||||
obs_data_set_bool(obj, "switch_if_not_matching",
|
||||
switcher->switchIfNotMatching);
|
||||
switcher->switchIfNotMatching);
|
||||
obs_data_set_bool(obj, "active", switcher->th.joinable());
|
||||
obs_data_set_array(obj, "switches", array);
|
||||
|
||||
|
|
@ -389,8 +381,8 @@ static void SaveSceneSwitcher(obs_data_t *save_data, bool saving, void *)
|
|||
} else {
|
||||
switcher->m.lock();
|
||||
|
||||
obs_data_t *obj = obs_data_get_obj(save_data,
|
||||
"auto-scene-switcher");
|
||||
obs_data_t *obj =
|
||||
obs_data_get_obj(save_data, "auto-scene-switcher");
|
||||
obs_data_array_t *array = obs_data_get_array(obj, "switches");
|
||||
size_t count = obs_data_array_count(array);
|
||||
|
||||
|
|
@ -420,8 +412,7 @@ static void SaveSceneSwitcher(obs_data_t *save_data, bool saving, void *)
|
|||
obs_data_get_string(array_obj, "window_title");
|
||||
|
||||
switcher->switches.emplace_back(
|
||||
GetWeakSourceByName(scene),
|
||||
window);
|
||||
GetWeakSourceByName(scene), window);
|
||||
|
||||
obs_data_release(array_obj);
|
||||
}
|
||||
|
|
@ -476,18 +467,18 @@ void SwitcherData::Thread()
|
|||
for (SceneSwitch &s : switches) {
|
||||
try {
|
||||
bool matches = regex_match(
|
||||
title, s.re);
|
||||
title, s.re);
|
||||
if (matches) {
|
||||
match = true;
|
||||
scene = s.scene;
|
||||
break;
|
||||
}
|
||||
} catch (const regex_error &) {}
|
||||
} catch (const regex_error &) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!match && switchIfNotMatching &&
|
||||
nonMatchingScene) {
|
||||
if (!match && switchIfNotMatching && nonMatchingScene) {
|
||||
match = true;
|
||||
scene = nonMatchingScene;
|
||||
}
|
||||
|
|
@ -513,7 +504,7 @@ void SwitcherData::Thread()
|
|||
void SwitcherData::Start()
|
||||
{
|
||||
if (!switcher->th.joinable())
|
||||
switcher->th = thread([] () {switcher->Thread();});
|
||||
switcher->th = thread([]() { switcher->Thread(); });
|
||||
}
|
||||
|
||||
void SwitcherData::Stop()
|
||||
|
|
@ -542,17 +533,16 @@ static void OBSEvent(enum obs_frontend_event event, void *)
|
|||
|
||||
extern "C" void InitSceneSwitcher()
|
||||
{
|
||||
QAction *action = (QAction*)obs_frontend_add_tools_menu_qaction(
|
||||
obs_module_text("SceneSwitcher"));
|
||||
QAction *action = (QAction *)obs_frontend_add_tools_menu_qaction(
|
||||
obs_module_text("SceneSwitcher"));
|
||||
|
||||
switcher = new SwitcherData;
|
||||
|
||||
auto cb = [] ()
|
||||
{
|
||||
auto cb = []() {
|
||||
obs_frontend_push_ui_translation(obs_module_get_string);
|
||||
|
||||
QMainWindow *window =
|
||||
(QMainWindow*)obs_frontend_get_main_window();
|
||||
(QMainWindow *)obs_frontend_get_main_window();
|
||||
|
||||
SceneSwitcher ss(window);
|
||||
ss.exec();
|
||||
|
|
|
|||
|
|
@ -1,33 +1,24 @@
|
|||
#include "captions-handler.hpp"
|
||||
|
||||
captions_handler::captions_handler(
|
||||
captions_cb callback,
|
||||
enum audio_format format,
|
||||
uint32_t sample_rate)
|
||||
captions_handler::captions_handler(captions_cb callback,
|
||||
enum audio_format format,
|
||||
uint32_t sample_rate)
|
||||
: cb(callback)
|
||||
{
|
||||
if (!reset_resampler(format, sample_rate))
|
||||
throw CAPTIONS_ERROR_GENERIC_FAIL;
|
||||
}
|
||||
|
||||
bool captions_handler::reset_resampler(
|
||||
enum audio_format format,
|
||||
uint32_t sample_rate)
|
||||
bool captions_handler::reset_resampler(enum audio_format format,
|
||||
uint32_t sample_rate)
|
||||
try {
|
||||
obs_audio_info ai;
|
||||
if (!obs_get_audio_info(&ai))
|
||||
throw std::string("Failed to get OBS audio info");
|
||||
|
||||
resample_info src = {
|
||||
ai.samples_per_sec,
|
||||
AUDIO_FORMAT_FLOAT_PLANAR,
|
||||
ai.speakers
|
||||
};
|
||||
resample_info dst = {
|
||||
sample_rate,
|
||||
format,
|
||||
SPEAKERS_MONO
|
||||
};
|
||||
resample_info src = {ai.samples_per_sec, AUDIO_FORMAT_FLOAT_PLANAR,
|
||||
ai.speakers};
|
||||
resample_info dst = {sample_rate, format, SPEAKERS_MONO};
|
||||
|
||||
if (!resampler.reset(dst, src))
|
||||
throw std::string("Failed to create audio resampler");
|
||||
|
|
@ -46,9 +37,9 @@ void captions_handler::push_audio(const audio_data *audio)
|
|||
uint64_t ts_offset;
|
||||
bool success;
|
||||
|
||||
success = audio_resampler_resample(resampler,
|
||||
out, &frames, &ts_offset,
|
||||
(const uint8_t *const *)audio->data, audio->frames);
|
||||
success = audio_resampler_resample(resampler, out, &frames, &ts_offset,
|
||||
(const uint8_t *const *)audio->data,
|
||||
audio->frames);
|
||||
if (success)
|
||||
pcm_data(out[0], frames);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,10 +9,7 @@ class resampler_obj {
|
|||
audio_resampler_t *resampler = nullptr;
|
||||
|
||||
public:
|
||||
inline ~resampler_obj()
|
||||
{
|
||||
audio_resampler_destroy(resampler);
|
||||
}
|
||||
inline ~resampler_obj() { audio_resampler_destroy(resampler); }
|
||||
|
||||
inline bool reset(const resample_info &dst, const resample_info &src)
|
||||
{
|
||||
|
|
@ -21,15 +18,15 @@ public:
|
|||
return !!resampler;
|
||||
}
|
||||
|
||||
inline operator audio_resampler_t*() {return resampler;}
|
||||
inline operator audio_resampler_t *() { return resampler; }
|
||||
};
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
typedef std::function<void (const std::string &)> captions_cb;
|
||||
typedef std::function<void(const std::string &)> captions_cb;
|
||||
|
||||
#define captions_error(s) std::string(obs_module_text("Captions.Error." ## s))
|
||||
#define CAPTIONS_ERROR_GENERIC_FAIL captions_error("GenericFail")
|
||||
#define captions_error(s) std::string(obs_module_text("Captions.Error."##s))
|
||||
#define CAPTIONS_ERROR_GENERIC_FAIL captions_error("GenericFail")
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
|
|
@ -38,22 +35,17 @@ class captions_handler {
|
|||
resampler_obj resampler;
|
||||
|
||||
protected:
|
||||
inline void callback(const std::string &text)
|
||||
{
|
||||
cb(text);
|
||||
}
|
||||
inline void callback(const std::string &text) { cb(text); }
|
||||
|
||||
virtual void pcm_data(const void *data, size_t frames)=0;
|
||||
virtual void pcm_data(const void *data, size_t frames) = 0;
|
||||
|
||||
/* always resamples to 1 channel */
|
||||
bool reset_resampler(enum audio_format format, uint32_t sample_rate);
|
||||
|
||||
public:
|
||||
/* throw std::string for errors shown to users */
|
||||
captions_handler(
|
||||
captions_cb callback,
|
||||
enum audio_format format,
|
||||
uint32_t sample_rate);
|
||||
captions_handler(captions_cb callback, enum audio_format format,
|
||||
uint32_t sample_rate);
|
||||
virtual ~captions_handler() {}
|
||||
|
||||
void push_audio(const audio_data *audio);
|
||||
|
|
@ -62,6 +54,6 @@ public:
|
|||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
struct captions_handler_info {
|
||||
std::string (*name)(void);
|
||||
std::string (*name)(void);
|
||||
captions_handler *(*create)(captions_cb cb, const std::string &lang);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -8,16 +8,17 @@
|
|||
using namespace std;
|
||||
|
||||
#if 0
|
||||
#define debugfunc(format, ...) blog(LOG_DEBUG, "[Captions] %s(" format ")", \
|
||||
__FUNCTION__, ##__VA_ARGS__)
|
||||
#define debugfunc(format, ...) \
|
||||
blog(LOG_DEBUG, "[Captions] %s(" format ")", __FUNCTION__, \
|
||||
##__VA_ARGS__)
|
||||
#else
|
||||
#define debugfunc(format, ...)
|
||||
#endif
|
||||
|
||||
CaptionStream::CaptionStream(DWORD samplerate_, mssapi_captions *handler_) :
|
||||
handler(handler_),
|
||||
samplerate(samplerate_),
|
||||
event(CreateEvent(nullptr, false, false, nullptr))
|
||||
CaptionStream::CaptionStream(DWORD samplerate_, mssapi_captions *handler_)
|
||||
: handler(handler_),
|
||||
samplerate(samplerate_),
|
||||
event(CreateEvent(nullptr, false, false, nullptr))
|
||||
{
|
||||
buf_info.ulMsMinNotification = 50;
|
||||
buf_info.ulMsBufferSize = 500;
|
||||
|
|
@ -66,15 +67,15 @@ STDMETHODIMP CaptionStream::QueryInterface(REFIID riid, void **ppv)
|
|||
|
||||
} else if (riid == IID_IStream) {
|
||||
AddRef();
|
||||
*ppv = (IStream*)this;
|
||||
*ppv = (IStream *)this;
|
||||
|
||||
} else if (riid == IID_ISpStreamFormat) {
|
||||
AddRef();
|
||||
*ppv = (ISpStreamFormat*)this;
|
||||
*ppv = (ISpStreamFormat *)this;
|
||||
|
||||
} else if (riid == IID_ISpAudio) {
|
||||
AddRef();
|
||||
*ppv = (ISpAudio*)this;
|
||||
*ppv = (ISpAudio *)this;
|
||||
|
||||
} else {
|
||||
*ppv = nullptr;
|
||||
|
|
@ -134,8 +135,7 @@ STDMETHODIMP CaptionStream::Read(void *data, ULONG bytes, ULONG *read_bytes)
|
|||
return hr;
|
||||
}
|
||||
|
||||
STDMETHODIMP CaptionStream::Write(const void *, ULONG bytes,
|
||||
ULONG*)
|
||||
STDMETHODIMP CaptionStream::Write(const void *, ULONG bytes, ULONG *)
|
||||
{
|
||||
debugfunc("data, %lu, written_bytes", bytes);
|
||||
UNUSED_PARAMETER(bytes);
|
||||
|
|
@ -146,7 +146,7 @@ STDMETHODIMP CaptionStream::Write(const void *, ULONG bytes,
|
|||
// IStream methods
|
||||
|
||||
STDMETHODIMP CaptionStream::Seek(LARGE_INTEGER move, DWORD origin,
|
||||
ULARGE_INTEGER *new_pos)
|
||||
ULARGE_INTEGER *new_pos)
|
||||
{
|
||||
debugfunc("%lld, %lx, new_pos", move, origin);
|
||||
UNUSED_PARAMETER(move);
|
||||
|
|
@ -170,8 +170,8 @@ STDMETHODIMP CaptionStream::SetSize(ULARGE_INTEGER new_size)
|
|||
}
|
||||
|
||||
STDMETHODIMP CaptionStream::CopyTo(IStream *stream, ULARGE_INTEGER bytes,
|
||||
ULARGE_INTEGER *read_bytes,
|
||||
ULARGE_INTEGER *written_bytes)
|
||||
ULARGE_INTEGER *read_bytes,
|
||||
ULARGE_INTEGER *written_bytes)
|
||||
{
|
||||
HRESULT hr;
|
||||
|
||||
|
|
@ -213,7 +213,7 @@ STDMETHODIMP CaptionStream::Revert(void)
|
|||
}
|
||||
|
||||
STDMETHODIMP CaptionStream::LockRegion(ULARGE_INTEGER offset,
|
||||
ULARGE_INTEGER size, DWORD type)
|
||||
ULARGE_INTEGER size, DWORD type)
|
||||
{
|
||||
debugfunc("%llu, %llu, %ld", offset, size, type);
|
||||
UNUSED_PARAMETER(offset);
|
||||
|
|
@ -224,7 +224,7 @@ STDMETHODIMP CaptionStream::LockRegion(ULARGE_INTEGER offset,
|
|||
}
|
||||
|
||||
STDMETHODIMP CaptionStream::UnlockRegion(ULARGE_INTEGER offset,
|
||||
ULARGE_INTEGER size, DWORD type)
|
||||
ULARGE_INTEGER size, DWORD type)
|
||||
{
|
||||
debugfunc("%llu, %llu, %ld", offset, size, type);
|
||||
UNUSED_PARAMETER(offset);
|
||||
|
|
@ -250,7 +250,7 @@ STDMETHODIMP CaptionStream::Stat(STATSTG *stg, DWORD flag)
|
|||
|
||||
if (flag == STATFLAG_DEFAULT) {
|
||||
size_t byte_size = (wcslen(stat_name) + 1) * sizeof(wchar_t);
|
||||
stg->pwcsName = (wchar_t*)CoTaskMemAlloc(byte_size);
|
||||
stg->pwcsName = (wchar_t *)CoTaskMemAlloc(byte_size);
|
||||
memcpy(stg->pwcsName, stat_name, byte_size);
|
||||
}
|
||||
|
||||
|
|
@ -267,7 +267,7 @@ STDMETHODIMP CaptionStream::Clone(IStream **stream)
|
|||
// ISpStreamFormat methods
|
||||
|
||||
STDMETHODIMP CaptionStream::GetFormat(GUID *guid,
|
||||
WAVEFORMATEX **co_mem_wfex_out)
|
||||
WAVEFORMATEX **co_mem_wfex_out)
|
||||
{
|
||||
debugfunc("guid, co_mem_wfex_out");
|
||||
|
||||
|
|
@ -282,7 +282,7 @@ STDMETHODIMP CaptionStream::GetFormat(GUID *guid,
|
|||
void *wfex = CoTaskMemAlloc(sizeof(format));
|
||||
memcpy(wfex, &format, sizeof(format));
|
||||
|
||||
*co_mem_wfex_out = (WAVEFORMATEX*)wfex;
|
||||
*co_mem_wfex_out = (WAVEFORMATEX *)wfex;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
|
@ -296,7 +296,7 @@ STDMETHODIMP CaptionStream::SetState(SPAUDIOSTATE state_, ULONGLONG)
|
|||
}
|
||||
|
||||
STDMETHODIMP CaptionStream::SetFormat(REFGUID guid_ref,
|
||||
const WAVEFORMATEX *wfex)
|
||||
const WAVEFORMATEX *wfex)
|
||||
{
|
||||
debugfunc("guid, wfex");
|
||||
if (!wfex)
|
||||
|
|
@ -306,7 +306,7 @@ STDMETHODIMP CaptionStream::SetFormat(REFGUID guid_ref,
|
|||
lock_guard<mutex> lock(m);
|
||||
memcpy(&format, wfex, sizeof(format));
|
||||
if (!handler->reset_resampler(AUDIO_FORMAT_16BIT,
|
||||
wfex->nSamplesPerSec))
|
||||
wfex->nSamplesPerSec))
|
||||
return E_FAIL;
|
||||
|
||||
/* 50 msec */
|
||||
|
|
@ -354,7 +354,7 @@ STDMETHODIMP CaptionStream::GetBufferInfo(SPAUDIOBUFFERINFO *buf_info_)
|
|||
}
|
||||
|
||||
STDMETHODIMP CaptionStream::GetDefaultFormat(GUID *format,
|
||||
WAVEFORMATEX **co_mem_wfex_out)
|
||||
WAVEFORMATEX **co_mem_wfex_out)
|
||||
{
|
||||
debugfunc("format, co_mem_wfex_out");
|
||||
|
||||
|
|
@ -365,7 +365,7 @@ STDMETHODIMP CaptionStream::GetDefaultFormat(GUID *format,
|
|||
memcpy(wfex, &format, sizeof(format));
|
||||
|
||||
*format = SPDFID_WaveFormatEx;
|
||||
*co_mem_wfex_out = (WAVEFORMATEX*)wfex;
|
||||
*co_mem_wfex_out = (WAVEFORMATEX *)wfex;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -13,10 +13,11 @@
|
|||
|
||||
class CircleBuf {
|
||||
circlebuf buf = {};
|
||||
|
||||
public:
|
||||
inline ~CircleBuf() {circlebuf_free(&buf);}
|
||||
inline operator circlebuf*() {return &buf;}
|
||||
inline circlebuf *operator->() {return &buf;}
|
||||
inline ~CircleBuf() { circlebuf_free(&buf); }
|
||||
inline operator circlebuf *() { return &buf; }
|
||||
inline circlebuf *operator->() { return &buf; }
|
||||
};
|
||||
|
||||
class mssapi_captions;
|
||||
|
|
@ -54,38 +55,38 @@ public:
|
|||
|
||||
// ISequentialStream methods
|
||||
STDMETHODIMP Read(void *data, ULONG bytes, ULONG *read_bytes) override;
|
||||
STDMETHODIMP Write(const void *data, ULONG bytes, ULONG *written_bytes)
|
||||
override;
|
||||
STDMETHODIMP Write(const void *data, ULONG bytes,
|
||||
ULONG *written_bytes) override;
|
||||
|
||||
// IStream methods
|
||||
STDMETHODIMP Seek(LARGE_INTEGER move, DWORD origin,
|
||||
ULARGE_INTEGER *new_pos) override;
|
||||
ULARGE_INTEGER *new_pos) override;
|
||||
STDMETHODIMP SetSize(ULARGE_INTEGER new_size) override;
|
||||
STDMETHODIMP CopyTo(IStream *stream, ULARGE_INTEGER bytes,
|
||||
ULARGE_INTEGER *read_bytes,
|
||||
ULARGE_INTEGER *written_bytes) override;
|
||||
ULARGE_INTEGER *read_bytes,
|
||||
ULARGE_INTEGER *written_bytes) override;
|
||||
STDMETHODIMP Commit(DWORD commit_flags) override;
|
||||
STDMETHODIMP Revert(void) override;
|
||||
STDMETHODIMP LockRegion(ULARGE_INTEGER offset, ULARGE_INTEGER size,
|
||||
DWORD type) override;
|
||||
DWORD type) override;
|
||||
STDMETHODIMP UnlockRegion(ULARGE_INTEGER offset, ULARGE_INTEGER size,
|
||||
DWORD type) override;
|
||||
DWORD type) override;
|
||||
STDMETHODIMP Stat(STATSTG *stg, DWORD flags) override;
|
||||
STDMETHODIMP Clone(IStream **stream) override;
|
||||
|
||||
// ISpStreamFormat methods
|
||||
STDMETHODIMP GetFormat(GUID *guid, WAVEFORMATEX **co_mem_wfex_out)
|
||||
override;
|
||||
STDMETHODIMP GetFormat(GUID *guid,
|
||||
WAVEFORMATEX **co_mem_wfex_out) override;
|
||||
|
||||
// ISpAudio methods
|
||||
STDMETHODIMP SetState(SPAUDIOSTATE state, ULONGLONG reserved) override;
|
||||
STDMETHODIMP SetFormat(REFGUID guid_ref, const WAVEFORMATEX *wfex)
|
||||
override;
|
||||
STDMETHODIMP SetFormat(REFGUID guid_ref,
|
||||
const WAVEFORMATEX *wfex) override;
|
||||
STDMETHODIMP GetStatus(SPAUDIOSTATUS *status) override;
|
||||
STDMETHODIMP SetBufferInfo(const SPAUDIOBUFFERINFO *buf_info) override;
|
||||
STDMETHODIMP GetBufferInfo(SPAUDIOBUFFERINFO *buf_info) override;
|
||||
STDMETHODIMP GetDefaultFormat(GUID *format,
|
||||
WAVEFORMATEX **co_mem_wfex_out) override;
|
||||
WAVEFORMATEX **co_mem_wfex_out) override;
|
||||
STDMETHODIMP_(HANDLE) EventHandle(void) override;
|
||||
STDMETHODIMP GetVolumeLevel(ULONG *level) override;
|
||||
STDMETHODIMP SetVolumeLevel(ULONG level) override;
|
||||
|
|
|
|||
|
|
@ -1,16 +1,13 @@
|
|||
#include "captions-mssapi.hpp"
|
||||
|
||||
#define do_log(type, format, ...) blog(type, "[Captions] " format, \
|
||||
##__VA_ARGS__)
|
||||
#define do_log(type, format, ...) \
|
||||
blog(type, "[Captions] " format, ##__VA_ARGS__)
|
||||
|
||||
#define error(format, ...) do_log(LOG_ERROR, format, ##__VA_ARGS__)
|
||||
#define debug(format, ...) do_log(LOG_DEBUG, format, ##__VA_ARGS__)
|
||||
|
||||
mssapi_captions::mssapi_captions(
|
||||
captions_cb callback,
|
||||
const std::string &lang) try
|
||||
: captions_handler(callback, AUDIO_FORMAT_16BIT, 16000)
|
||||
{
|
||||
mssapi_captions::mssapi_captions(captions_cb callback, const std::string &lang)
|
||||
try : captions_handler(callback, AUDIO_FORMAT_16BIT, 16000) {
|
||||
HRESULT hr;
|
||||
|
||||
std::wstring wlang;
|
||||
|
|
@ -33,7 +30,7 @@ mssapi_captions::mssapi_captions(
|
|||
throw HRError("SpFindBestToken failed", hr);
|
||||
|
||||
hr = CoCreateInstance(CLSID_SpInprocRecognizer, nullptr, CLSCTX_ALL,
|
||||
__uuidof(ISpRecognizer), (void**)&recognizer);
|
||||
__uuidof(ISpRecognizer), (void **)&recognizer);
|
||||
if (FAILED(hr))
|
||||
throw HRError("CoCreateInstance for recognizer failed", hr);
|
||||
|
||||
|
|
@ -50,7 +47,7 @@ mssapi_captions::mssapi_captions(
|
|||
throw HRError("CreateRecoContext failed", hr);
|
||||
|
||||
ULONGLONG interest = SPFEI(SPEI_RECOGNITION) |
|
||||
SPFEI(SPEI_END_SR_STREAM);
|
||||
SPFEI(SPEI_END_SR_STREAM);
|
||||
hr = context->SetInterest(interest, interest);
|
||||
if (FAILED(hr))
|
||||
throw HRError("SetInterest failed", hr);
|
||||
|
|
@ -80,7 +77,7 @@ mssapi_captions::mssapi_captions(
|
|||
throw HRError("LoadDictation failed", hr);
|
||||
|
||||
try {
|
||||
t = std::thread([this] () {main_thread();});
|
||||
t = std::thread([this]() { main_thread(); });
|
||||
} catch (...) {
|
||||
throw "Failed to create thread";
|
||||
}
|
||||
|
|
@ -133,8 +130,8 @@ try {
|
|||
ISpRecoResult *result = event.RecoResult();
|
||||
|
||||
CoTaskMemPtr<wchar_t> text;
|
||||
hr = result->GetText((ULONG)-1, (ULONG)-1,
|
||||
true, &text, nullptr);
|
||||
hr = result->GetText((ULONG)-1, (ULONG)-1, true,
|
||||
&text, nullptr);
|
||||
if (FAILED(hr))
|
||||
continue;
|
||||
|
||||
|
|
@ -168,12 +165,7 @@ void mssapi_captions::pcm_data(const void *data, size_t frames)
|
|||
}
|
||||
|
||||
captions_handler_info mssapi_info = {
|
||||
[] () -> std::string
|
||||
{
|
||||
return "Microsoft Speech-to-Text";
|
||||
},
|
||||
[] (captions_cb cb, const std::string &lang) -> captions_handler *
|
||||
{
|
||||
[]() -> std::string { return "Microsoft Speech-to-Text"; },
|
||||
[](captions_cb cb, const std::string &lang) -> captions_handler * {
|
||||
return new mssapi_captions(cb, lang);
|
||||
}
|
||||
};
|
||||
}};
|
||||
|
|
|
|||
|
|
@ -27,16 +27,16 @@
|
|||
class mssapi_captions : public captions_handler {
|
||||
friend class CaptionStream;
|
||||
|
||||
ComPtr<CaptionStream> audio;
|
||||
ComPtr<CaptionStream> audio;
|
||||
ComPtr<ISpObjectToken> token;
|
||||
ComPtr<ISpRecoGrammar> grammar;
|
||||
ComPtr<ISpRecognizer> recognizer;
|
||||
ComPtr<ISpRecognizer> recognizer;
|
||||
ComPtr<ISpRecoContext> context;
|
||||
|
||||
HANDLE notify;
|
||||
WinHandle stop;
|
||||
std::thread t;
|
||||
bool started = false;
|
||||
HANDLE notify;
|
||||
WinHandle stop;
|
||||
std::thread t;
|
||||
bool started = false;
|
||||
|
||||
void main_thread();
|
||||
|
||||
|
|
|
|||
|
|
@ -31,8 +31,8 @@
|
|||
|
||||
#include "captions-mssapi.hpp"
|
||||
|
||||
#define do_log(type, format, ...) blog(type, "[Captions] " format, \
|
||||
##__VA_ARGS__)
|
||||
#define do_log(type, format, ...) \
|
||||
blog(type, "[Captions] " format, ##__VA_ARGS__)
|
||||
|
||||
#define warn(format, ...) do_log(LOG_WARNING, format, ##__VA_ARGS__)
|
||||
#define debug(format, ...) do_log(LOG_DEBUG, format, ##__VA_ARGS__)
|
||||
|
|
@ -48,10 +48,10 @@ struct obs_captions {
|
|||
unique_ptr<captions_handler> handler;
|
||||
LANGID lang_id = GetUserDefaultUILanguage();
|
||||
|
||||
std::unordered_map<std::string, captions_handler_info&> handler_types;
|
||||
std::unordered_map<std::string, captions_handler_info &> handler_types;
|
||||
|
||||
inline void register_handler(const char *id,
|
||||
captions_handler_info &info)
|
||||
captions_handler_info &info)
|
||||
{
|
||||
handler_types.emplace(id, info);
|
||||
}
|
||||
|
|
@ -60,7 +60,7 @@ struct obs_captions {
|
|||
void stop();
|
||||
|
||||
obs_captions();
|
||||
inline ~obs_captions() {stop();}
|
||||
inline ~obs_captions() { stop(); }
|
||||
};
|
||||
|
||||
static obs_captions *captions = nullptr;
|
||||
|
|
@ -74,9 +74,9 @@ struct locale_info {
|
|||
inline locale_info() {}
|
||||
inline locale_info(const locale_info &) = delete;
|
||||
inline locale_info(locale_info &&li)
|
||||
: name(std::move(li.name)),
|
||||
id(li.id)
|
||||
{}
|
||||
: name(std::move(li.name)), id(li.id)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
static void get_valid_locale_names(vector<locale_info> &names);
|
||||
|
|
@ -84,16 +84,14 @@ static bool valid_lang(LANGID id);
|
|||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
CaptionsDialog::CaptionsDialog(QWidget *parent) :
|
||||
QDialog(parent),
|
||||
ui(new Ui_CaptionsDialog)
|
||||
CaptionsDialog::CaptionsDialog(QWidget *parent)
|
||||
: QDialog(parent), ui(new Ui_CaptionsDialog)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
|
||||
|
||||
auto cb = [this] (obs_source_t *source)
|
||||
{
|
||||
auto cb = [this](obs_source_t *source) {
|
||||
uint32_t caps = obs_source_get_output_flags(source);
|
||||
QString name = obs_source_get_name(source);
|
||||
|
||||
|
|
@ -111,8 +109,11 @@ CaptionsDialog::CaptionsDialog(QWidget *parent) :
|
|||
ui->source->blockSignals(true);
|
||||
ui->source->addItem(QStringLiteral(""));
|
||||
ui->source->setCurrentIndex(0);
|
||||
obs_enum_sources([] (void *data, obs_source_t *source) {
|
||||
return (*static_cast<cb_t*>(data))(source);}, &cb);
|
||||
obs_enum_sources(
|
||||
[](void *data, obs_source_t *source) {
|
||||
return (*static_cast<cb_t *>(data))(source);
|
||||
},
|
||||
&cb);
|
||||
ui->source->blockSignals(false);
|
||||
|
||||
for (auto &ht : captions->handler_types) {
|
||||
|
|
@ -232,8 +233,8 @@ static void caption_text(const std::string &text)
|
|||
}
|
||||
}
|
||||
|
||||
static void audio_capture(void*, obs_source_t*,
|
||||
const struct audio_data *audio, bool)
|
||||
static void audio_capture(void *, obs_source_t *,
|
||||
const struct audio_data *audio, bool)
|
||||
{
|
||||
captions->handler->push_audio(audio);
|
||||
}
|
||||
|
|
@ -245,14 +246,13 @@ void obs_captions::start()
|
|||
|
||||
auto pair = handler_types.find(handler_id);
|
||||
if (pair == handler_types.end()) {
|
||||
warn("Failed to find handler '%s'",
|
||||
handler_id.c_str());
|
||||
warn("Failed to find handler '%s'", handler_id.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
if (!LCIDToLocaleName(lang_id, wname, 256, 0)) {
|
||||
warn("Failed to get locale name: %d",
|
||||
(int)GetLastError());
|
||||
(int)GetLastError());
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -271,24 +271,24 @@ void obs_captions::start()
|
|||
}
|
||||
|
||||
try {
|
||||
captions_handler *h = pair->second.create(caption_text,
|
||||
lang_name);
|
||||
captions_handler *h =
|
||||
pair->second.create(caption_text, lang_name);
|
||||
handler.reset(h);
|
||||
|
||||
OBSSource s = OBSGetStrongRef(source);
|
||||
obs_source_add_audio_capture_callback(s,
|
||||
audio_capture, nullptr);
|
||||
obs_source_add_audio_capture_callback(s, audio_capture,
|
||||
nullptr);
|
||||
|
||||
} catch (std::string text) {
|
||||
QWidget *window =
|
||||
(QWidget*)obs_frontend_get_main_window();
|
||||
(QWidget *)obs_frontend_get_main_window();
|
||||
|
||||
warn("Failed to create handler: %s", text.c_str());
|
||||
|
||||
QMessageBox::warning(window,
|
||||
QMessageBox::warning(
|
||||
window,
|
||||
obs_module_text("Captions.Error.GenericFail"),
|
||||
text.c_str());
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -297,8 +297,8 @@ void obs_captions::stop()
|
|||
{
|
||||
OBSSource s = OBSGetStrongRef(source);
|
||||
if (s)
|
||||
obs_source_remove_audio_capture_callback(s,
|
||||
audio_capture, nullptr);
|
||||
obs_source_remove_audio_capture_callback(s, audio_capture,
|
||||
nullptr);
|
||||
handler.reset();
|
||||
}
|
||||
|
||||
|
|
@ -332,42 +332,18 @@ static void get_valid_locale_names(vector<locale_info> &locales)
|
|||
char locale_name[256];
|
||||
|
||||
static const LANGID default_locales[] = {
|
||||
0x0409,
|
||||
0x0401,
|
||||
0x0402,
|
||||
0x0403,
|
||||
0x0404,
|
||||
0x0405,
|
||||
0x0406,
|
||||
0x0407,
|
||||
0x0408,
|
||||
0x040a,
|
||||
0x040b,
|
||||
0x040c,
|
||||
0x040d,
|
||||
0x040e,
|
||||
0x040f,
|
||||
0x0410,
|
||||
0x0411,
|
||||
0x0412,
|
||||
0x0413,
|
||||
0x0414,
|
||||
0x0415,
|
||||
0x0416,
|
||||
0x0417,
|
||||
0x0418,
|
||||
0x0419,
|
||||
0x041a,
|
||||
0
|
||||
};
|
||||
0x0409, 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0406,
|
||||
0x0407, 0x0408, 0x040a, 0x040b, 0x040c, 0x040d, 0x040e,
|
||||
0x040f, 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415,
|
||||
0x0416, 0x0417, 0x0418, 0x0419, 0x041a, 0};
|
||||
|
||||
/* ---------------------------------- */
|
||||
|
||||
LANGID def_id = GetUserDefaultUILanguage();
|
||||
LANGID id = def_id;
|
||||
if (valid_lang(id) && get_locale_name(id, locale_name)) {
|
||||
dstr_copy(cur.name, obs_module_text(
|
||||
"Captions.CurrentSystemLanguage"));
|
||||
dstr_copy(cur.name,
|
||||
obs_module_text("Captions.CurrentSystemLanguage"));
|
||||
dstr_replace(cur.name, "%1", locale_name);
|
||||
cur.id = id;
|
||||
|
||||
|
|
@ -381,8 +357,7 @@ static void get_valid_locale_names(vector<locale_info> &locales)
|
|||
while (*locale) {
|
||||
id = *locale;
|
||||
|
||||
if (id != def_id &&
|
||||
valid_lang(id) &&
|
||||
if (id != def_id && valid_lang(id) &&
|
||||
get_locale_name(id, locale_name)) {
|
||||
|
||||
dstr_copy(cur.name, locale_name);
|
||||
|
|
@ -418,17 +393,17 @@ static void obs_event(enum obs_frontend_event event, void *)
|
|||
FreeCaptions();
|
||||
}
|
||||
|
||||
static void save_caption_data(obs_data_t *save_data, bool saving, void*)
|
||||
static void save_caption_data(obs_data_t *save_data, bool saving, void *)
|
||||
{
|
||||
if (saving) {
|
||||
obs_data_t *obj = obs_data_create();
|
||||
|
||||
obs_data_set_string(obj, "source",
|
||||
captions->source_name.c_str());
|
||||
captions->source_name.c_str());
|
||||
obs_data_set_bool(obj, "enabled", !!captions->handler);
|
||||
obs_data_set_int(obj, "lang_id", captions->lang_id);
|
||||
obs_data_set_string(obj, "provider",
|
||||
captions->handler_id.c_str());
|
||||
captions->handler_id.c_str());
|
||||
|
||||
obs_data_set_obj(save_data, "captions", obj);
|
||||
obs_data_release(obj);
|
||||
|
|
@ -440,15 +415,15 @@ static void save_caption_data(obs_data_t *save_data, bool saving, void*)
|
|||
obj = obs_data_create();
|
||||
|
||||
obs_data_set_default_int(obj, "lang_id",
|
||||
GetUserDefaultUILanguage());
|
||||
GetUserDefaultUILanguage());
|
||||
obs_data_set_default_string(obj, "provider", DEFAULT_HANDLER);
|
||||
|
||||
bool enabled = obs_data_get_bool(obj, "enabled");
|
||||
captions->source_name = obs_data_get_string(obj, "source");
|
||||
captions->lang_id = (int)obs_data_get_int(obj, "lang_id");
|
||||
captions->handler_id = obs_data_get_string(obj, "provider");
|
||||
captions->source = GetWeakSourceByName(
|
||||
captions->source_name.c_str());
|
||||
captions->source =
|
||||
GetWeakSourceByName(captions->source_name.c_str());
|
||||
obs_data_release(obj);
|
||||
|
||||
if (enabled)
|
||||
|
|
@ -458,17 +433,15 @@ static void save_caption_data(obs_data_t *save_data, bool saving, void*)
|
|||
|
||||
extern "C" void InitCaptions()
|
||||
{
|
||||
QAction *action = (QAction*)obs_frontend_add_tools_menu_qaction(
|
||||
obs_module_text("Captions"));
|
||||
QAction *action = (QAction *)obs_frontend_add_tools_menu_qaction(
|
||||
obs_module_text("Captions"));
|
||||
|
||||
captions = new obs_captions;
|
||||
|
||||
auto cb = [] ()
|
||||
{
|
||||
auto cb = []() {
|
||||
obs_frontend_push_ui_translation(obs_module_get_string);
|
||||
|
||||
QWidget *window =
|
||||
(QWidget*)obs_frontend_get_main_window();
|
||||
QWidget *window = (QWidget *)obs_frontend_get_main_window();
|
||||
|
||||
CaptionsDialog dialog(window);
|
||||
dialog.exec();
|
||||
|
|
|
|||
7
UI/frontend-plugins/frontend-tools/data/locale/af-ZA.ini
Normal file
7
UI/frontend-plugins/frontend-tools/data/locale/af-ZA.ini
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
Start="Begin"
|
||||
Stop="Stop"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -24,6 +24,7 @@ OutputTimer.Stream.StoppingIn="سيتم إيقاف البث بعد:"
|
|||
OutputTimer.Record.StoppingIn="سيتم إيقاف التسجيل بعد:"
|
||||
OutputTimer.Stream.EnableEverytime="تفعيل مؤقِّت البث في كل مرة"
|
||||
OutputTimer.Record.EnableEverytime="تفعيل مؤقِّت التسجيل في كل مرة"
|
||||
OutputTimer.Record.PauseTimer="إيقاف المُؤَقِت عندما يكون التسجيل متوقف"
|
||||
|
||||
Scripts="سكريبتات"
|
||||
LoadedScripts="السكريبتات المحملة"
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ OutputTimer.Stream.StoppingIn="La transmissió s'aturarà en:"
|
|||
OutputTimer.Record.StoppingIn="La gravació s'aturarà en:"
|
||||
OutputTimer.Stream.EnableEverytime="Activa el temporitzador en cada transmissió"
|
||||
OutputTimer.Record.EnableEverytime="Activa el temporitzador en cada enregistrament"
|
||||
OutputTimer.Record.PauseTimer="Pausa el temporitzador en pausar l'enregistrament"
|
||||
|
||||
Scripts="Scripts"
|
||||
LoadedScripts="Scripts carregats"
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ OutputTimer.Stream.StoppingIn="Vysílání se zastaví za:"
|
|||
OutputTimer.Record.StoppingIn="Nahrávání se zastaví za:"
|
||||
OutputTimer.Stream.EnableEverytime="Pokaždé povolit časovač vysílání"
|
||||
OutputTimer.Record.EnableEverytime="Pokaždé povolit časovač nahrávání"
|
||||
OutputTimer.Record.PauseTimer="Pozastavit časovač při pozastavení nahrávání"
|
||||
|
||||
Scripts="Skripty"
|
||||
LoadedScripts="Načtené skripty"
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ OutputTimer.Stream.StoppingIn="Streaming standser om:"
|
|||
OutputTimer.Record.StoppingIn="Optagelse standser om:"
|
||||
OutputTimer.Stream.EnableEverytime="Aktivér streamingtimer hver gang"
|
||||
OutputTimer.Record.EnableEverytime="Aktivér optagetimer hver gang"
|
||||
OutputTimer.Record.PauseTimer="Sæt timer på pause, når optagelsen er sat på pause"
|
||||
|
||||
Scripts="Scripts"
|
||||
LoadedScripts="Indlæste scripts"
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ SceneSwitcher.OnNoMatch.DontSwitch="Nicht wechseln"
|
|||
SceneSwitcher.OnNoMatch.SwitchTo="Wechseln zu:"
|
||||
SceneSwitcher.CheckInterval="Titel des aktiven Fensters überprüfen alle:"
|
||||
SceneSwitcher.ActiveOrNotActive="Szenenwechsler ist:"
|
||||
InvalidRegex.Title="Ungültiger regulärer Ausdruck"
|
||||
InvalidRegex.Title="Ungültiger, regulärer Ausdruck"
|
||||
InvalidRegex.Text="Der reguläre Ausdruck, den Sie eingegeben haben, ist ungültig."
|
||||
Active="Aktiv"
|
||||
Inactive="Inaktiv"
|
||||
|
|
@ -24,16 +24,17 @@ OutputTimer.Stream.StoppingIn="Stream stoppt in:"
|
|||
OutputTimer.Record.StoppingIn="Aufnahme stoppt in:"
|
||||
OutputTimer.Stream.EnableEverytime="Streamingtimer jedes Mal aktivieren"
|
||||
OutputTimer.Record.EnableEverytime="Aufnahmetimer jedes Mal aktivieren"
|
||||
OutputTimer.Record.PauseTimer="Timer beim Pausieren der Aufnahme anhalten"
|
||||
|
||||
Scripts="Skripte"
|
||||
LoadedScripts="Geladene Skripte"
|
||||
AddScripts="Skripte hinzufügen"
|
||||
RemoveScripts="Skripte entfernen"
|
||||
ReloadScripts="Skripte neu laden"
|
||||
PythonSettings="Python-Einstellungen"
|
||||
PythonSettings.PythonInstallPath32bit="Python-Installationspfad (32bit)"
|
||||
PythonSettings.PythonInstallPath64bit="Python-Installationspfad (64bit)"
|
||||
PythonSettings.BrowsePythonPath="Python-Pfad öffnen"
|
||||
ReloadScripts="Skripte neuladen"
|
||||
PythonSettings="Python‐Einstellungen"
|
||||
PythonSettings.PythonInstallPath32bit="Python‐Installationspfad (32bit)"
|
||||
PythonSettings.PythonInstallPath64bit="Python‐Installationspfad (64bit)"
|
||||
PythonSettings.BrowsePythonPath="Python‐Pfad öffnen"
|
||||
ScriptLogWindow="Skriptprotokoll"
|
||||
Description="Beschreibung"
|
||||
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ OutputTimer.Stream.StoppingIn="Streaming stopping in:"
|
|||
OutputTimer.Record.StoppingIn="Recording stopping in:"
|
||||
OutputTimer.Stream.EnableEverytime="Enable streaming timer every time"
|
||||
OutputTimer.Record.EnableEverytime="Enable recording timer every time"
|
||||
OutputTimer.Record.PauseTimer="Pause timer when recording is paused"
|
||||
|
||||
Scripts="Scripts"
|
||||
LoadedScripts="Loaded Scripts"
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ OutputTimer.Stream.StoppingIn="Finalizando transmisión en:"
|
|||
OutputTimer.Record.StoppingIn="Finalizando grabación en:"
|
||||
OutputTimer.Stream.EnableEverytime="Activar temporizador en cada transmisión"
|
||||
OutputTimer.Record.EnableEverytime="Activar temporizador en cada grabación"
|
||||
OutputTimer.Record.PauseTimer="Pausar temporizador cuando la grabación se pause"
|
||||
|
||||
Scripts="Scripts"
|
||||
LoadedScripts="Scripts Cargados"
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ OutputTimer.Stream.StoppingIn="Transmisioa geldituko da: hau barru:"
|
|||
OutputTimer.Record.StoppingIn="Grabazioa geldituko da hau barru:"
|
||||
OutputTimer.Stream.EnableEverytime="Gaitu transmisio tenporizadorea aldiro"
|
||||
OutputTimer.Record.EnableEverytime="Gaitu grabazio tenporizadorea aldiro"
|
||||
OutputTimer.Record.PauseTimer="Pausatu tenporizadorea grabazioa pausatuta dagoenean"
|
||||
|
||||
Scripts="Script-ak"
|
||||
LoadedScripts="Kargatutako script-ak"
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ OutputTimer.Stream.StoppingIn="Arrêt du streaming dans :"
|
|||
OutputTimer.Record.StoppingIn="Arrêt de l'enregistrement dans :"
|
||||
OutputTimer.Stream.EnableEverytime="Démarrer le minuteur automatiquement à chaque stream"
|
||||
OutputTimer.Record.EnableEverytime="Démarrer le minuteur automatiquement à chaque enregistrement"
|
||||
OutputTimer.Record.PauseTimer="Mettre en pause le minuteur quand l'enregistrement est mis en pause"
|
||||
|
||||
Scripts="Scripts"
|
||||
LoadedScripts="Scripts chargés"
|
||||
|
|
|
|||
43
UI/frontend-plugins/frontend-tools/data/locale/gl-ES.ini
Normal file
43
UI/frontend-plugins/frontend-tools/data/locale/gl-ES.ini
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
SceneSwitcher="Conmutador automático de escena"
|
||||
SceneSwitcher.OnNoMatch="Cando non coincida ningunha xanela:"
|
||||
SceneSwitcher.OnNoMatch.DontSwitch="Non conmutar"
|
||||
SceneSwitcher.OnNoMatch.SwitchTo="Cambiar a:"
|
||||
SceneSwitcher.CheckInterval="Comprobar o título da xanela activa cada:"
|
||||
SceneSwitcher.ActiveOrNotActive="O conmutador de escena está:"
|
||||
InvalidRegex.Title="Expresión regular non válida"
|
||||
InvalidRegex.Text="A expresión regular que introduciu non é válida."
|
||||
Active="Activo"
|
||||
Inactive="Inactivo"
|
||||
Start="Iniciar"
|
||||
Stop="Parar"
|
||||
|
||||
Captions="Subtítulos (experimental)"
|
||||
Captions.AudioSource="Fonte de son"
|
||||
Captions.CurrentSystemLanguage="Idioma actual do sistema (%1)"
|
||||
Captions.Provider="Fornecedor"
|
||||
Captions.Error.GenericFail="Produciuse un erro ao iniciar os suntítulos"
|
||||
|
||||
OutputTimer="Temporizador de Saída"
|
||||
OutputTimer.Stream="Deter a emisión após:"
|
||||
OutputTimer.Record="Deter a gravación após:"
|
||||
OutputTimer.Stream.StoppingIn="Detendo a emisión en:"
|
||||
OutputTimer.Record.StoppingIn="Detendo a gravación en:"
|
||||
OutputTimer.Stream.EnableEverytime="Activar o temporizador en cada emisión"
|
||||
OutputTimer.Record.EnableEverytime="Activar o temporizador en cada gravación"
|
||||
OutputTimer.Record.PauseTimer="Pór en pausa o temporizador ao pór en pausa a gravación"
|
||||
|
||||
Scripts="Scripts"
|
||||
LoadedScripts="Scripts cargados"
|
||||
AddScripts="Engadir scripts"
|
||||
RemoveScripts="Retirar scripts"
|
||||
ReloadScripts="Volver cargar scripts"
|
||||
PythonSettings="Axustes de Python"
|
||||
PythonSettings.PythonInstallPath32bit="Ruta de instalación de Python (32bit)"
|
||||
PythonSettings.PythonInstallPath64bit="Ruta de instalación de Python (64bit)"
|
||||
PythonSettings.BrowsePythonPath="Examinar a ruta de Python"
|
||||
ScriptLogWindow="Rexistro de script"
|
||||
Description="Descrición"
|
||||
|
||||
FileFilter.ScriptFiles="Ficheiros de scripts"
|
||||
FileFilter.AllFiles="Todos os ficheiros"
|
||||
|
||||
|
|
@ -24,6 +24,7 @@ OutputTimer.Stream.StoppingIn="A stream leáll:"
|
|||
OutputTimer.Record.StoppingIn="Felvétel leáll:"
|
||||
OutputTimer.Stream.EnableEverytime="Stream időzítő indítása minden alkalommal"
|
||||
OutputTimer.Record.EnableEverytime="Felvétel időzítő indítása minden alkalommal"
|
||||
OutputTimer.Record.PauseTimer="Idő megállítása, ha a felvétel is megáll"
|
||||
|
||||
Scripts="Szkriptek"
|
||||
LoadedScripts="Betöltött szkriptek"
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ OutputTimer.Stream.StoppingIn="La diretta terminerà tra:"
|
|||
OutputTimer.Record.StoppingIn="La registrazione terminerà tra:"
|
||||
OutputTimer.Stream.EnableEverytime="Attiva il conto alla rovescia per le dirette ogni volta"
|
||||
OutputTimer.Record.EnableEverytime="Attiva il conto alla rovescia per le registrazioni ogni volta"
|
||||
OutputTimer.Record.PauseTimer="Pausa il timer quando la registrazione è in pausa"
|
||||
|
||||
Scripts="Script"
|
||||
LoadedScripts="Script caricati"
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ OutputTimer.Stream.StoppingIn="配信停止まで:"
|
|||
OutputTimer.Record.StoppingIn="録画停止まで:"
|
||||
OutputTimer.Stream.EnableEverytime="毎回配信タイマーを有効にする"
|
||||
OutputTimer.Record.EnableEverytime="毎回録画タイマーを有効にする"
|
||||
OutputTimer.Record.PauseTimer="録画が一時停止したときにタイマーを一時停止"
|
||||
|
||||
Scripts="スクリプト"
|
||||
LoadedScripts="ロードしたスクリプト"
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ OutputTimer.Stream.StoppingIn="ნაკადის შეწყვეტის
|
|||
OutputTimer.Record.StoppingIn="ჩაწერის შეწყვეტის დრო:"
|
||||
OutputTimer.Stream.EnableEverytime="ნაკადის წამზომის ჩართვა ყოველ ჯერზე"
|
||||
OutputTimer.Record.EnableEverytime="ჩაწერის წამზომის ჩართვა ყოველ ჯერზე"
|
||||
OutputTimer.Record.PauseTimer="წამზომის შეჩერება ჩაწერის შეჩერებისას"
|
||||
|
||||
Scripts="სკრიპტები"
|
||||
LoadedScripts="ჩატვირთული სკრიპტები"
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ OutputTimer.Stream.StoppingIn="방송 중지까지 남은 시간:"
|
|||
OutputTimer.Record.StoppingIn="녹화 중지까지 남은 시간:"
|
||||
OutputTimer.Stream.EnableEverytime="매번 방송 시간 기록기 활성화"
|
||||
OutputTimer.Record.EnableEverytime="매번 녹화 시간 기록기 활성화"
|
||||
OutputTimer.Record.PauseTimer="녹화가 중지되었을 때 타이머 일시 정지"
|
||||
|
||||
Scripts="스크립트"
|
||||
LoadedScripts="입력한 스크립트"
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ OutputTimer.Stream.StoppingIn="Stream stopt over:"
|
|||
OutputTimer.Record.StoppingIn="Opname stopt over:"
|
||||
OutputTimer.Stream.EnableEverytime="Schakel streaming timer elke keer in"
|
||||
OutputTimer.Record.EnableEverytime="Schakel opnametimer elke keer in"
|
||||
OutputTimer.Record.PauseTimer="Pauzeer timer tijdens het pauzeren van de opname"
|
||||
|
||||
Scripts="Scripts"
|
||||
LoadedScripts="Geladen Scripts"
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ OutputTimer.Stream.StoppingIn="Zatrzymanie streamu za:"
|
|||
OutputTimer.Record.StoppingIn="Zatrzymanie nagrywania za:"
|
||||
OutputTimer.Stream.EnableEverytime="Włącz timer streamu za każdym razem"
|
||||
OutputTimer.Record.EnableEverytime="Włącz timer nagrywania za każdym razem"
|
||||
OutputTimer.Record.PauseTimer="Zatrzymaj czas, gdy nagrywanie jest spauzowane"
|
||||
|
||||
Scripts="Skrypty"
|
||||
LoadedScripts="Wczytane skrypty"
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ OutputTimer.Stream.StoppingIn="A transmissão irá parar em:"
|
|||
OutputTimer.Record.StoppingIn="A gravação irá parar em:"
|
||||
OutputTimer.Stream.EnableEverytime="Ativar o timer streaming o tempo todo"
|
||||
OutputTimer.Record.EnableEverytime="Ativar o timer de gravação o tempo todo"
|
||||
OutputTimer.Record.PauseTimer="Pausar o temporizador quando a gravação é pausada"
|
||||
|
||||
Scripts="Scripts"
|
||||
LoadedScripts="Scripts Carregados"
|
||||
|
|
|
|||
|
|
@ -10,11 +10,11 @@ Start="Pornește"
|
|||
Stop="Oprește"
|
||||
|
||||
Captions="Subtitrări (experimentale)"
|
||||
Captions.AudioSource="Sursa audio"
|
||||
Captions.AudioSource="Sursă audio"
|
||||
Captions.CurrentSystemLanguage="Limba actuală a sistemului (%1)"
|
||||
Captions.Provider="Furnizor"
|
||||
|
||||
OutputTimer.Record="Opriți înregistrarea după:"
|
||||
OutputTimer.Record="Oprește înregistrarea după:"
|
||||
OutputTimer.Stream.StoppingIn="Se oprește transmisiunea în:"
|
||||
OutputTimer.Record.StoppingIn="Înregistrarea se oprește în:"
|
||||
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ OutputTimer.Stream.StoppingIn="Стрим будет завершён через
|
|||
OutputTimer.Record.StoppingIn="Запись будет завершена через:"
|
||||
OutputTimer.Stream.EnableEverytime="Включать таймер трансляции каждый раз"
|
||||
OutputTimer.Record.EnableEverytime="Включать таймер записи каждый раз"
|
||||
OutputTimer.Record.PauseTimer="Таймер паузы при приостановке записи"
|
||||
|
||||
Scripts="Скрипты"
|
||||
LoadedScripts="Загруженные скрипты"
|
||||
|
|
|
|||
43
UI/frontend-plugins/frontend-tools/data/locale/sl-SI.ini
Normal file
43
UI/frontend-plugins/frontend-tools/data/locale/sl-SI.ini
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
SceneSwitcher="Samodejno preklapljanje prizorov"
|
||||
SceneSwitcher.OnNoMatch="Ko se nobeno okno ne ujema:"
|
||||
SceneSwitcher.OnNoMatch.DontSwitch="Ne preklopi"
|
||||
SceneSwitcher.OnNoMatch.SwitchTo="Preklopi na:"
|
||||
SceneSwitcher.CheckInterval="Preveri naziv dejavnega okna vsakih:"
|
||||
SceneSwitcher.ActiveOrNotActive="Preklopnik prizorov je:"
|
||||
InvalidRegex.Title="Neveljaven regularni izraz"
|
||||
InvalidRegex.Text="Vneseni regularni izraz ni veljaven."
|
||||
Active="Dejaven"
|
||||
Inactive="Nedejaven"
|
||||
Start="Začni"
|
||||
Stop="Ustavi"
|
||||
|
||||
Captions="Napisi (preizkusno)"
|
||||
Captions.AudioSource="Zvočni vir"
|
||||
Captions.CurrentSystemLanguage="Trenutni jezik sistema (%1)"
|
||||
Captions.Provider="Ponudnik"
|
||||
Captions.Error.GenericFail="Zagon napisov je spodletel"
|
||||
|
||||
OutputTimer="Odštevalnik izhoda"
|
||||
OutputTimer.Stream="Prenehaj pretakati po:"
|
||||
OutputTimer.Record="Prenehaj snemati po:"
|
||||
OutputTimer.Stream.StoppingIn="Pretok se bo ustavil čez:"
|
||||
OutputTimer.Record.StoppingIn="Snemanje se bo ustavilo čez:"
|
||||
OutputTimer.Stream.EnableEverytime="Vsakič omogoči odštevalnik pretakanja"
|
||||
OutputTimer.Record.EnableEverytime="Vsakič omogoči odštevalnik snemanja"
|
||||
OutputTimer.Record.PauseTimer="Premor odštevalnika ob premoru snemanja"
|
||||
|
||||
Scripts="Skripti"
|
||||
LoadedScripts="Naloženi skripti"
|
||||
AddScripts="Dodaj skripte"
|
||||
RemoveScripts="Odstrani skripte"
|
||||
ReloadScripts="Ponovno naloži skripte"
|
||||
PythonSettings="Nastavitve Python"
|
||||
PythonSettings.PythonInstallPath32bit="Namestitvena pot Pythona (32-bitni)"
|
||||
PythonSettings.PythonInstallPath64bit="Namestitvena pot Pythona (64-bitni)"
|
||||
PythonSettings.BrowsePythonPath="Prebrskaj pot do Pythona"
|
||||
ScriptLogWindow="Dnevnik skriptov"
|
||||
Description="Opis"
|
||||
|
||||
FileFilter.ScriptFiles="Datoteke skriptov"
|
||||
FileFilter.AllFiles="Vse datoteke"
|
||||
|
||||
|
|
@ -24,6 +24,7 @@ OutputTimer.Stream.StoppingIn="Streamen stoppas om:"
|
|||
OutputTimer.Record.StoppingIn="Inspelningen stoppas om:"
|
||||
OutputTimer.Stream.EnableEverytime="Aktivera strömtimer varje gång"
|
||||
OutputTimer.Record.EnableEverytime="Aktivera inspelningstimer varje gång"
|
||||
OutputTimer.Record.PauseTimer="Pausa timer när inspelning pausas"
|
||||
|
||||
Scripts="Skript"
|
||||
LoadedScripts="Inlästa skript"
|
||||
|
|
|
|||
|
|
@ -1,3 +1,8 @@
|
|||
SceneSwitcher="สลับฉากอัตโนมัติ"
|
||||
SceneSwitcher.OnNoMatch="เมื่อหน้าต่างไม่สัมพันธ์กัน:"
|
||||
SceneSwitcher.OnNoMatch.DontSwitch="ไม่สลับ"
|
||||
SceneSwitcher.OnNoMatch.SwitchTo="สลับไปยัง:"
|
||||
SceneSwitcher.CheckInterval="ตรวจสอบหน้าต่างที่ถูกเลือกทุกๆ"
|
||||
Active="ใช้งานอยู่"
|
||||
Inactive="ไม่ใช้งาน"
|
||||
Start="เริ่ม"
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ OutputTimer.Stream.StoppingIn="Yayın durduruluyor:"
|
|||
OutputTimer.Record.StoppingIn="Kayıt durduruluyor:"
|
||||
OutputTimer.Stream.EnableEverytime="Her zaman yayın zamanlayıcıyı etkinleştir"
|
||||
OutputTimer.Record.EnableEverytime="Her zaman kayıt zamanlayıcıyı etkinleştir"
|
||||
OutputTimer.Record.PauseTimer="Kayıt durdurulduğunda sayacı durdur"
|
||||
|
||||
Scripts="Betikler"
|
||||
LoadedScripts="Yüklü Betikler"
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ OutputTimer.Stream.StoppingIn="Трансляція припиниться за:
|
|||
OutputTimer.Record.StoppingIn="Запис зупиниться за:"
|
||||
OutputTimer.Stream.EnableEverytime="Щоразу запускається трансляція - вмикати Таймер для Виводу"
|
||||
OutputTimer.Record.EnableEverytime="Щоразу починається запис - вмикати Таймер для Виводу"
|
||||
OutputTimer.Record.PauseTimer="Призупиняти таймер коли запис Призупинено"
|
||||
|
||||
Scripts="Скрипти"
|
||||
LoadedScripts="Завантажені скрипти"
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ OutputTimer.Stream.StoppingIn="串流停止在:"
|
|||
OutputTimer.Record.StoppingIn="录制停止在:"
|
||||
OutputTimer.Stream.EnableEverytime="每次启用流计时器"
|
||||
OutputTimer.Record.EnableEverytime="每次启用录制计时器"
|
||||
OutputTimer.Record.PauseTimer="暂停录制时暂停计时器"
|
||||
|
||||
Scripts="脚本"
|
||||
LoadedScripts="已载入脚本"
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ OutputTimer.Stream.StoppingIn="串流將在下面時間內停止"
|
|||
OutputTimer.Record.StoppingIn="錄影將在下面時間內停止"
|
||||
OutputTimer.Stream.EnableEverytime="每次都啟動串流計時器"
|
||||
OutputTimer.Record.EnableEverytime="每次都啟動錄影計時器"
|
||||
OutputTimer.Record.PauseTimer="錄影暫停時,計時器也暫停。"
|
||||
|
||||
Scripts="腳本"
|
||||
LoadedScripts="已載入腳本"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,44 @@
|
|||
obs = obslua
|
||||
pause_scene = ""
|
||||
|
||||
function on_event(event)
|
||||
if event == obs.OBS_FRONTEND_EVENT_SCENE_CHANGED then
|
||||
local scene = obs.obs_frontend_get_current_scene()
|
||||
local scene_name = obs.obs_source_get_name(scene)
|
||||
if pause_scene == scene_name then
|
||||
obs.obs_frontend_recording_pause(true)
|
||||
else
|
||||
obs.obs_frontend_recording_pause(false)
|
||||
end
|
||||
|
||||
obs.obs_source_release(scene);
|
||||
end
|
||||
end
|
||||
|
||||
function script_properties()
|
||||
local props = obs.obs_properties_create()
|
||||
|
||||
local p = obs.obs_properties_add_list(props, "pause_scene", "Pause Scene", obs.OBS_COMBO_TYPE_EDITABLE, obs.OBS_COMBO_FORMAT_STRING)
|
||||
local scenes = obs.obs_frontend_get_scenes()
|
||||
if scenes ~= nil then
|
||||
for _, scene in ipairs(scenes) do
|
||||
local name = obs.obs_source_get_name(scene);
|
||||
obs.obs_property_list_add_string(p, name, name)
|
||||
end
|
||||
end
|
||||
obs.source_list_release(scenes)
|
||||
|
||||
return props
|
||||
end
|
||||
|
||||
function script_description()
|
||||
return "Adds the ability to pause recording when switching to a specific scene"
|
||||
end
|
||||
|
||||
function script_update(settings)
|
||||
pause_scene = obs.obs_data_get_string(settings, "pause_scene")
|
||||
end
|
||||
|
||||
function script_load(settings)
|
||||
obs.obs_frontend_add_event_callback(on_event)
|
||||
end
|
||||
|
|
@ -1,215 +1,237 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>OutputTimer</class>
|
||||
<widget class="QDialog" name="OutputTimer">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>600</width>
|
||||
<height>200</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>OutputTimer</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="timerLayout">
|
||||
<item row="0" column="1">
|
||||
<widget class="QLabel" name="streamingLabel">
|
||||
<property name="text">
|
||||
<string>OutputTimer.Stream</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<widget class="QSpinBox" name="streamingTimerHours">
|
||||
<property name="minimum">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>24</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>0</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="3">
|
||||
<widget class="QLabel" name="hoursLabel">
|
||||
<property name="text">
|
||||
<string>Hours</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="4">
|
||||
<widget class="QSpinBox" name="streamingTimerMinutes">
|
||||
<property name="maximum">
|
||||
<number>59</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>0</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="5">
|
||||
<widget class="QLabel" name="minutesLabel">
|
||||
<property name="text">
|
||||
<string>Minutes</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="6">
|
||||
<widget class="QSpinBox" name="streamingTimerSeconds">
|
||||
<property name="minimum">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>59</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>30</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="7">
|
||||
<widget class="QLabel" name="secondsLabel">
|
||||
<property name="text">
|
||||
<string>Seconds</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="8">
|
||||
<widget class="QPushButton" name="outputTimerStream">
|
||||
<property name="text">
|
||||
<string>Start</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QLabel" name="streamStoppingIn">
|
||||
<property name="text">
|
||||
<string>OutputTimer.Stream.StoppingIn</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="2">
|
||||
<widget class="QLabel" name="streamTime">
|
||||
<property name="text">
|
||||
<string>00:00:00</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QLabel" name="recordingLabel">
|
||||
<property name="text">
|
||||
<string>OutputTimer.Record</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="2">
|
||||
<widget class="QSpinBox" name="recordingTimerHours">
|
||||
<property name="minimum">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>24</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>0</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="3">
|
||||
<widget class="QLabel" name="hoursLabel_2">
|
||||
<property name="text">
|
||||
<string>Hours</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="4">
|
||||
<widget class="QSpinBox" name="recordingTimerMinutes">
|
||||
<property name="minimum">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>59</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>0</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="5">
|
||||
<widget class="QLabel" name="minutesLabel_2">
|
||||
<property name="text">
|
||||
<string>Minutes</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="6">
|
||||
<widget class="QSpinBox" name="recordingTimerSeconds">
|
||||
<property name="minimum">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>59</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>30</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="7">
|
||||
<widget class="QLabel" name="secondsLabel_2">
|
||||
<property name="text">
|
||||
<string>Seconds</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="8">
|
||||
<widget class="QPushButton" name="outputTimerRecord">
|
||||
<property name="text">
|
||||
<string>Start</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="1">
|
||||
<widget class="QLabel" name="recordStoppingIn">
|
||||
<property name="text">
|
||||
<string>OutputTimer.Record.StoppingIn</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="2">
|
||||
<widget class="QLabel" name="recordTime">
|
||||
<property name="text">
|
||||
<string>00:00:00</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1" colspan="3">
|
||||
<widget class="QCheckBox" name="autoStartStreamTimer">
|
||||
<property name="text">
|
||||
<string>OutputTimer.Stream.EnableEverytime</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1" colspan="3">
|
||||
<widget class="QCheckBox" name="autoStartRecordTimer">
|
||||
<property name="text">
|
||||
<string>OutputTimer.Record.EnableEverytime</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="8">
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Close</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources />
|
||||
<connections />
|
||||
<widget class="QDialog" name="OutputTimer">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>697</width>
|
||||
<height>240</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>OutputTimer</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="timerLayout">
|
||||
<item row="0" column="3">
|
||||
<widget class="QLabel" name="hoursLabel">
|
||||
<property name="text">
|
||||
<string>Hours</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="2">
|
||||
<widget class="QSpinBox" name="recordingTimerHours">
|
||||
<property name="minimum">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>24</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>0</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="6">
|
||||
<widget class="QSpinBox" name="streamingTimerSeconds">
|
||||
<property name="minimum">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>59</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>30</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="8">
|
||||
<widget class="QPushButton" name="outputTimerStream">
|
||||
<property name="text">
|
||||
<string>Start</string>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="4">
|
||||
<widget class="QSpinBox" name="recordingTimerMinutes">
|
||||
<property name="minimum">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>59</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>0</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLabel" name="streamingLabel">
|
||||
<property name="text">
|
||||
<string>OutputTimer.Stream</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="4">
|
||||
<widget class="QSpinBox" name="streamingTimerMinutes">
|
||||
<property name="maximum">
|
||||
<number>59</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>0</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="8">
|
||||
<widget class="QPushButton" name="outputTimerRecord">
|
||||
<property name="text">
|
||||
<string>Start</string>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="1">
|
||||
<widget class="QLabel" name="recordStoppingIn">
|
||||
<property name="text">
|
||||
<string>OutputTimer.Record.StoppingIn</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="7">
|
||||
<widget class="QLabel" name="secondsLabel_2">
|
||||
<property name="text">
|
||||
<string>Seconds</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="2">
|
||||
<widget class="QLabel" name="streamTime">
|
||||
<property name="text">
|
||||
<string>00:00:00</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="5">
|
||||
<widget class="QLabel" name="minutesLabel_2">
|
||||
<property name="text">
|
||||
<string>Minutes</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<widget class="QSpinBox" name="streamingTimerHours">
|
||||
<property name="minimum">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>24</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>0</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="2">
|
||||
<widget class="QLabel" name="recordTime">
|
||||
<property name="text">
|
||||
<string>00:00:00</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="5">
|
||||
<widget class="QLabel" name="minutesLabel">
|
||||
<property name="text">
|
||||
<string>Minutes</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QLabel" name="recordingLabel">
|
||||
<property name="text">
|
||||
<string>OutputTimer.Record</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="6">
|
||||
<widget class="QSpinBox" name="recordingTimerSeconds">
|
||||
<property name="minimum">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>59</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>30</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1" colspan="3">
|
||||
<widget class="QCheckBox" name="autoStartStreamTimer">
|
||||
<property name="text">
|
||||
<string>OutputTimer.Stream.EnableEverytime</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QLabel" name="streamStoppingIn">
|
||||
<property name="text">
|
||||
<string>OutputTimer.Stream.StoppingIn</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1" colspan="3">
|
||||
<widget class="QCheckBox" name="autoStartRecordTimer">
|
||||
<property name="text">
|
||||
<string>OutputTimer.Record.EnableEverytime</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="8">
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Close</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="3">
|
||||
<widget class="QLabel" name="hoursLabel_2">
|
||||
<property name="text">
|
||||
<string>Hours</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="7">
|
||||
<widget class="QLabel" name="secondsLabel">
|
||||
<property name="text">
|
||||
<string>Seconds</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="1" colspan="3">
|
||||
<widget class="QCheckBox" name="pauseRecordTimer">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>OutputTimer.Record.PauseTimer</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
|
|
|
|||
|
|
@ -13,19 +13,18 @@ using namespace std;
|
|||
OutputTimer *ot;
|
||||
|
||||
OutputTimer::OutputTimer(QWidget *parent)
|
||||
: QDialog(parent),
|
||||
ui(new Ui_OutputTimer)
|
||||
: QDialog(parent), ui(new Ui_OutputTimer)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
|
||||
|
||||
QObject::connect(ui->outputTimerStream, SIGNAL(clicked()), this,
|
||||
SLOT(StreamingTimerButton()));
|
||||
SLOT(StreamingTimerButton()));
|
||||
QObject::connect(ui->outputTimerRecord, SIGNAL(clicked()), this,
|
||||
SLOT(RecordingTimerButton()));
|
||||
SLOT(RecordingTimerButton()));
|
||||
QObject::connect(ui->buttonBox->button(QDialogButtonBox::Close),
|
||||
SIGNAL(clicked()), this, SLOT(hide()));
|
||||
SIGNAL(clicked()), this, SLOT(hide()));
|
||||
|
||||
streamingTimer = new QTimer(this);
|
||||
streamingTimerDisplay = new QTimer(this);
|
||||
|
|
@ -34,7 +33,7 @@ OutputTimer::OutputTimer(QWidget *parent)
|
|||
recordingTimerDisplay = new QTimer(this);
|
||||
}
|
||||
|
||||
void OutputTimer::closeEvent(QCloseEvent*)
|
||||
void OutputTimer::closeEvent(QCloseEvent *)
|
||||
{
|
||||
obs_frontend_save();
|
||||
}
|
||||
|
|
@ -78,9 +77,7 @@ void OutputTimer::StreamTimerStart()
|
|||
int minutes = ui->streamingTimerMinutes->value();
|
||||
int seconds = ui->streamingTimerSeconds->value();
|
||||
|
||||
int total = (((hours * 3600) +
|
||||
(minutes * 60)) +
|
||||
seconds) * 1000;
|
||||
int total = (((hours * 3600) + (minutes * 60)) + seconds) * 1000;
|
||||
|
||||
if (total == 0)
|
||||
total = 1000;
|
||||
|
|
@ -89,16 +86,18 @@ void OutputTimer::StreamTimerStart()
|
|||
streamingTimer->setSingleShot(true);
|
||||
|
||||
QObject::connect(streamingTimer, SIGNAL(timeout()),
|
||||
SLOT(EventStopStreaming()));
|
||||
SLOT(EventStopStreaming()));
|
||||
|
||||
QObject::connect(streamingTimerDisplay, SIGNAL(timeout()), this,
|
||||
SLOT(UpdateStreamTimerDisplay()));
|
||||
SLOT(UpdateStreamTimerDisplay()));
|
||||
|
||||
streamingTimer->start();
|
||||
streamingTimerDisplay->start(1000);
|
||||
ui->outputTimerStream->setText(obs_module_text("Stop"));
|
||||
|
||||
UpdateStreamTimerDisplay();
|
||||
|
||||
ui->outputTimerStream->setChecked(true);
|
||||
}
|
||||
|
||||
void OutputTimer::RecordTimerStart()
|
||||
|
|
@ -112,9 +111,7 @@ void OutputTimer::RecordTimerStart()
|
|||
int minutes = ui->recordingTimerMinutes->value();
|
||||
int seconds = ui->recordingTimerSeconds->value();
|
||||
|
||||
int total = (((hours * 3600) +
|
||||
(minutes * 60)) +
|
||||
seconds) * 1000;
|
||||
int total = (((hours * 3600) + (minutes * 60)) + seconds) * 1000;
|
||||
|
||||
if (total == 0)
|
||||
total = 1000;
|
||||
|
|
@ -123,16 +120,18 @@ void OutputTimer::RecordTimerStart()
|
|||
recordingTimer->setSingleShot(true);
|
||||
|
||||
QObject::connect(recordingTimer, SIGNAL(timeout()),
|
||||
SLOT(EventStopRecording()));
|
||||
SLOT(EventStopRecording()));
|
||||
|
||||
QObject::connect(recordingTimerDisplay, SIGNAL(timeout()), this,
|
||||
SLOT(UpdateRecordTimerDisplay()));
|
||||
SLOT(UpdateRecordTimerDisplay()));
|
||||
|
||||
recordingTimer->start();
|
||||
recordingTimerDisplay->start(1000);
|
||||
ui->outputTimerRecord->setText(obs_module_text("Stop"));
|
||||
|
||||
UpdateRecordTimerDisplay();
|
||||
|
||||
ui->outputTimerRecord->setChecked(true);
|
||||
}
|
||||
|
||||
void OutputTimer::StreamTimerStop()
|
||||
|
|
@ -151,6 +150,7 @@ void OutputTimer::StreamTimerStop()
|
|||
streamingTimerDisplay->stop();
|
||||
|
||||
ui->streamTime->setText("00:00:00");
|
||||
ui->outputTimerStream->setChecked(false);
|
||||
}
|
||||
|
||||
void OutputTimer::RecordTimerStop()
|
||||
|
|
@ -169,6 +169,7 @@ void OutputTimer::RecordTimerStop()
|
|||
recordingTimerDisplay->stop();
|
||||
|
||||
ui->recordTime->setText("00:00:00");
|
||||
ui->outputTimerRecord->setChecked(false);
|
||||
}
|
||||
|
||||
void OutputTimer::UpdateStreamTimerDisplay()
|
||||
|
|
@ -186,7 +187,13 @@ void OutputTimer::UpdateStreamTimerDisplay()
|
|||
|
||||
void OutputTimer::UpdateRecordTimerDisplay()
|
||||
{
|
||||
int remainingTime = recordingTimer->remainingTime() / 1000;
|
||||
int remainingTime = 0;
|
||||
|
||||
if (obs_frontend_recording_paused() &&
|
||||
ui->pauseRecordTimer->isChecked())
|
||||
remainingTime = recordingTimeLeft / 1000;
|
||||
else
|
||||
remainingTime = recordingTimer->remainingTime() / 1000;
|
||||
|
||||
int seconds = remainingTime % 60;
|
||||
int minutes = (remainingTime % 3600) / 60;
|
||||
|
|
@ -197,6 +204,26 @@ void OutputTimer::UpdateRecordTimerDisplay()
|
|||
ui->recordTime->setText(text);
|
||||
}
|
||||
|
||||
void OutputTimer::PauseRecordingTimer()
|
||||
{
|
||||
if (!ui->pauseRecordTimer->isChecked())
|
||||
return;
|
||||
|
||||
if (recordingTimer->isActive()) {
|
||||
recordingTimeLeft = recordingTimer->remainingTime();
|
||||
recordingTimer->stop();
|
||||
}
|
||||
}
|
||||
|
||||
void OutputTimer::UnpauseRecordingTimer()
|
||||
{
|
||||
if (!ui->pauseRecordTimer->isChecked())
|
||||
return;
|
||||
|
||||
if (!recordingTimer->isActive())
|
||||
recordingTimer->start(recordingTimeLeft);
|
||||
}
|
||||
|
||||
void OutputTimer::ShowHideDialog()
|
||||
{
|
||||
if (!isVisible()) {
|
||||
|
|
@ -226,60 +253,63 @@ static void SaveOutputTimer(obs_data_t *save_data, bool saving, void *)
|
|||
obs_data_t *obj = obs_data_create();
|
||||
|
||||
obs_data_set_int(obj, "streamTimerHours",
|
||||
ot->ui->streamingTimerHours->value());
|
||||
ot->ui->streamingTimerHours->value());
|
||||
obs_data_set_int(obj, "streamTimerMinutes",
|
||||
ot->ui->streamingTimerMinutes->value());
|
||||
ot->ui->streamingTimerMinutes->value());
|
||||
obs_data_set_int(obj, "streamTimerSeconds",
|
||||
ot->ui->streamingTimerSeconds->value());
|
||||
ot->ui->streamingTimerSeconds->value());
|
||||
|
||||
obs_data_set_int(obj, "recordTimerHours",
|
||||
ot->ui->recordingTimerHours->value());
|
||||
ot->ui->recordingTimerHours->value());
|
||||
obs_data_set_int(obj, "recordTimerMinutes",
|
||||
ot->ui->recordingTimerMinutes->value());
|
||||
ot->ui->recordingTimerMinutes->value());
|
||||
obs_data_set_int(obj, "recordTimerSeconds",
|
||||
ot->ui->recordingTimerSeconds->value());
|
||||
ot->ui->recordingTimerSeconds->value());
|
||||
|
||||
obs_data_set_bool(obj, "autoStartStreamTimer",
|
||||
ot->ui->autoStartStreamTimer->isChecked());
|
||||
ot->ui->autoStartStreamTimer->isChecked());
|
||||
obs_data_set_bool(obj, "autoStartRecordTimer",
|
||||
ot->ui->autoStartRecordTimer->isChecked());
|
||||
ot->ui->autoStartRecordTimer->isChecked());
|
||||
|
||||
obs_data_set_bool(obj, "pauseRecordTimer",
|
||||
ot->ui->pauseRecordTimer->isChecked());
|
||||
|
||||
obs_data_set_obj(save_data, "output-timer", obj);
|
||||
|
||||
obs_data_release(obj);
|
||||
} else {
|
||||
obs_data_t *obj = obs_data_get_obj(save_data,
|
||||
"output-timer");
|
||||
obs_data_t *obj = obs_data_get_obj(save_data, "output-timer");
|
||||
|
||||
if (!obj)
|
||||
obj = obs_data_create();
|
||||
|
||||
ot->ui->streamingTimerHours->setValue(
|
||||
obs_data_get_int(obj, "streamTimerHours"));
|
||||
obs_data_get_int(obj, "streamTimerHours"));
|
||||
ot->ui->streamingTimerMinutes->setValue(
|
||||
obs_data_get_int(obj, "streamTimerMinutes"));
|
||||
obs_data_get_int(obj, "streamTimerMinutes"));
|
||||
ot->ui->streamingTimerSeconds->setValue(
|
||||
obs_data_get_int(obj, "streamTimerSeconds"));
|
||||
obs_data_get_int(obj, "streamTimerSeconds"));
|
||||
|
||||
ot->ui->recordingTimerHours->setValue(
|
||||
obs_data_get_int(obj, "recordTimerHours"));
|
||||
obs_data_get_int(obj, "recordTimerHours"));
|
||||
ot->ui->recordingTimerMinutes->setValue(
|
||||
obs_data_get_int(obj, "recordTimerMinutes"));
|
||||
obs_data_get_int(obj, "recordTimerMinutes"));
|
||||
ot->ui->recordingTimerSeconds->setValue(
|
||||
obs_data_get_int(obj, "recordTimerSeconds"));
|
||||
obs_data_get_int(obj, "recordTimerSeconds"));
|
||||
|
||||
ot->ui->autoStartStreamTimer->setChecked(
|
||||
obs_data_get_bool(obj, "autoStartStreamTimer"));
|
||||
obs_data_get_bool(obj, "autoStartStreamTimer"));
|
||||
ot->ui->autoStartRecordTimer->setChecked(
|
||||
obs_data_get_bool(obj, "autoStartRecordTimer"));
|
||||
obs_data_get_bool(obj, "autoStartRecordTimer"));
|
||||
|
||||
ot->ui->pauseRecordTimer->setChecked(
|
||||
obs_data_get_bool(obj, "pauseRecordTimer"));
|
||||
|
||||
obs_data_release(obj);
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" void FreeOutputTimer()
|
||||
{
|
||||
}
|
||||
extern "C" void FreeOutputTimer() {}
|
||||
|
||||
static void OBSEvent(enum obs_frontend_event event, void *)
|
||||
{
|
||||
|
|
@ -294,24 +324,25 @@ static void OBSEvent(enum obs_frontend_event event, void *)
|
|||
ot->RecordTimerStart();
|
||||
} else if (event == OBS_FRONTEND_EVENT_RECORDING_STOPPING) {
|
||||
ot->RecordTimerStop();
|
||||
} else if (event == OBS_FRONTEND_EVENT_RECORDING_PAUSED) {
|
||||
ot->PauseRecordingTimer();
|
||||
} else if (event == OBS_FRONTEND_EVENT_RECORDING_UNPAUSED) {
|
||||
ot->UnpauseRecordingTimer();
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" void InitOutputTimer()
|
||||
{
|
||||
QAction *action = (QAction*)obs_frontend_add_tools_menu_qaction(
|
||||
obs_module_text("OutputTimer"));
|
||||
QAction *action = (QAction *)obs_frontend_add_tools_menu_qaction(
|
||||
obs_module_text("OutputTimer"));
|
||||
|
||||
obs_frontend_push_ui_translation(obs_module_get_string);
|
||||
|
||||
QMainWindow *window = (QMainWindow*)obs_frontend_get_main_window();
|
||||
QMainWindow *window = (QMainWindow *)obs_frontend_get_main_window();
|
||||
|
||||
ot = new OutputTimer(window);
|
||||
|
||||
auto cb = [] ()
|
||||
{
|
||||
ot->ShowHideDialog();
|
||||
};
|
||||
auto cb = []() { ot->ShowHideDialog(); };
|
||||
|
||||
obs_frontend_pop_ui_translation();
|
||||
|
||||
|
|
|
|||
|
|
@ -15,6 +15,8 @@ public:
|
|||
OutputTimer(QWidget *parent);
|
||||
|
||||
void closeEvent(QCloseEvent *event) override;
|
||||
void PauseRecordingTimer();
|
||||
void UnpauseRecordingTimer();
|
||||
|
||||
public slots:
|
||||
void StreamingTimerButton();
|
||||
|
|
@ -37,4 +39,6 @@ private:
|
|||
QTimer *recordingTimer;
|
||||
QTimer *streamingTimerDisplay;
|
||||
QTimer *recordingTimerDisplay;
|
||||
|
||||
int recordingTimeLeft;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@
|
|||
|
||||
/* ----------------------------------------------------------------- */
|
||||
|
||||
using OBSScript = OBSObj<obs_script_t*, obs_script_destroy>;
|
||||
using OBSScript = OBSObj<obs_script_t *, obs_script_destroy>;
|
||||
|
||||
struct ScriptData {
|
||||
std::vector<OBSScript> scripts;
|
||||
|
|
@ -92,11 +92,10 @@ ScriptLogWindow::ScriptLogWindow() : QWidget(nullptr)
|
|||
|
||||
QHBoxLayout *buttonLayout = new QHBoxLayout();
|
||||
QPushButton *clearButton = new QPushButton(tr("Clear"));
|
||||
connect(clearButton, &QPushButton::clicked,
|
||||
this, &ScriptLogWindow::ClearWindow);
|
||||
connect(clearButton, &QPushButton::clicked, this,
|
||||
&ScriptLogWindow::ClearWindow);
|
||||
QPushButton *closeButton = new QPushButton(tr("Close"));
|
||||
connect(closeButton, &QPushButton::clicked,
|
||||
this, &QDialog::hide);
|
||||
connect(closeButton, &QPushButton::clicked, this, &QDialog::hide);
|
||||
|
||||
buttonLayout->addStretch();
|
||||
buttonLayout->addWidget(clearButton);
|
||||
|
|
@ -112,8 +111,8 @@ ScriptLogWindow::ScriptLogWindow() : QWidget(nullptr)
|
|||
resize(600, 400);
|
||||
|
||||
config_t *global_config = obs_frontend_get_global_config();
|
||||
const char *geom = config_get_string(global_config,
|
||||
"ScriptLogWindow", "geometry");
|
||||
const char *geom =
|
||||
config_get_string(global_config, "ScriptLogWindow", "geometry");
|
||||
if (geom != nullptr) {
|
||||
QByteArray ba = QByteArray::fromBase64(QByteArray(geom));
|
||||
restoreGeometry(ba);
|
||||
|
|
@ -121,16 +120,15 @@ ScriptLogWindow::ScriptLogWindow() : QWidget(nullptr)
|
|||
|
||||
setWindowTitle(obs_module_text("ScriptLogWindow"));
|
||||
|
||||
connect(edit->verticalScrollBar(), &QAbstractSlider::sliderMoved,
|
||||
this, &ScriptLogWindow::ScrollChanged);
|
||||
connect(edit->verticalScrollBar(), &QAbstractSlider::sliderMoved, this,
|
||||
&ScriptLogWindow::ScrollChanged);
|
||||
}
|
||||
|
||||
ScriptLogWindow::~ScriptLogWindow()
|
||||
{
|
||||
config_t *global_config = obs_frontend_get_global_config();
|
||||
config_set_string(global_config,
|
||||
"ScriptLogWindow", "geometry",
|
||||
saveGeometry().toBase64().constData());
|
||||
config_set_string(global_config, "ScriptLogWindow", "geometry",
|
||||
saveGeometry().toBase64().constData());
|
||||
}
|
||||
|
||||
void ScriptLogWindow::ScrollChanged(int val)
|
||||
|
|
@ -180,17 +178,15 @@ void ScriptLogWindow::Clear()
|
|||
|
||||
/* ----------------------------------------------------------------- */
|
||||
|
||||
ScriptsTool::ScriptsTool()
|
||||
: QWidget (nullptr),
|
||||
ui (new Ui_ScriptsTool)
|
||||
ScriptsTool::ScriptsTool() : QWidget(nullptr), ui(new Ui_ScriptsTool)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
RefreshLists();
|
||||
|
||||
#if PYTHON_UI
|
||||
config_t *config = obs_frontend_get_global_config();
|
||||
const char *path = config_get_string(config, "Python",
|
||||
"Path" ARCH_NAME);
|
||||
const char *path =
|
||||
config_get_string(config, "Python", "Path" ARCH_NAME);
|
||||
ui->pythonPath->setText(path);
|
||||
ui->pythonPathLabel->setText(obs_module_text(PYTHONPATH_LABEL_TEXT));
|
||||
#else
|
||||
|
|
@ -201,7 +197,7 @@ ScriptsTool::ScriptsTool()
|
|||
delete propertiesView;
|
||||
propertiesView = new QWidget();
|
||||
propertiesView->setSizePolicy(QSizePolicy::Expanding,
|
||||
QSizePolicy::Expanding);
|
||||
QSizePolicy::Expanding);
|
||||
ui->propertiesLayout->addWidget(propertiesView);
|
||||
}
|
||||
|
||||
|
|
@ -217,8 +213,8 @@ void ScriptsTool::RemoveScript(const char *path)
|
|||
|
||||
const char *script_path = obs_script_get_path(script);
|
||||
if (strcmp(script_path, path) == 0) {
|
||||
scriptData->scripts.erase(
|
||||
scriptData->scripts.begin() + i);
|
||||
scriptData->scripts.erase(scriptData->scripts.begin() +
|
||||
i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -323,7 +319,8 @@ void ScriptsTool::on_addScripts_clicked()
|
|||
|
||||
scriptData->scripts.emplace_back(script);
|
||||
|
||||
QListWidgetItem *item = new QListWidgetItem(script_file);
|
||||
QListWidgetItem *item =
|
||||
new QListWidgetItem(script_file);
|
||||
item->setData(Qt::UserRole, QString(file));
|
||||
ui->scripts->addItem(item);
|
||||
|
||||
|
|
@ -343,8 +340,10 @@ void ScriptsTool::on_removeScripts_clicked()
|
|||
QList<QListWidgetItem *> items = ui->scripts->selectedItems();
|
||||
|
||||
for (QListWidgetItem *item : items)
|
||||
RemoveScript(item->data(Qt::UserRole).toString()
|
||||
.toUtf8().constData());
|
||||
RemoveScript(item->data(Qt::UserRole)
|
||||
.toString()
|
||||
.toUtf8()
|
||||
.constData());
|
||||
RefreshLists();
|
||||
}
|
||||
|
||||
|
|
@ -352,8 +351,10 @@ void ScriptsTool::on_reloadScripts_clicked()
|
|||
{
|
||||
QList<QListWidgetItem *> items = ui->scripts->selectedItems();
|
||||
for (QListWidgetItem *item : items)
|
||||
ReloadScript(item->data(Qt::UserRole).toString()
|
||||
.toUtf8().constData());
|
||||
ReloadScript(item->data(Qt::UserRole)
|
||||
.toString()
|
||||
.toUtf8()
|
||||
.constData());
|
||||
|
||||
on_scripts_currentRowChanged(ui->scripts->currentRow());
|
||||
}
|
||||
|
|
@ -368,9 +369,7 @@ void ScriptsTool::on_pythonPathBrowse_clicked()
|
|||
{
|
||||
QString curPath = ui->pythonPath->text();
|
||||
QString newPath = QFileDialog::getExistingDirectory(
|
||||
this,
|
||||
ui->pythonPathLabel->text(),
|
||||
curPath);
|
||||
this, ui->pythonPathLabel->text(), curPath);
|
||||
|
||||
if (newPath.isEmpty())
|
||||
return;
|
||||
|
|
@ -406,14 +405,14 @@ void ScriptsTool::on_scripts_currentRowChanged(int row)
|
|||
if (row == -1) {
|
||||
propertiesView = new QWidget();
|
||||
propertiesView->setSizePolicy(QSizePolicy::Expanding,
|
||||
QSizePolicy::Expanding);
|
||||
QSizePolicy::Expanding);
|
||||
ui->propertiesLayout->addWidget(propertiesView);
|
||||
ui->description->setText(QString());
|
||||
return;
|
||||
}
|
||||
|
||||
QByteArray array = ui->scripts->item(row)->data(Qt::UserRole)
|
||||
.toString().toUtf8();
|
||||
QByteArray array =
|
||||
ui->scripts->item(row)->data(Qt::UserRole).toString().toUtf8();
|
||||
const char *path = array.constData();
|
||||
|
||||
obs_script_t *script = scriptData->FindScript(path);
|
||||
|
|
@ -425,9 +424,10 @@ void ScriptsTool::on_scripts_currentRowChanged(int row)
|
|||
OBSData settings = obs_script_get_settings(script);
|
||||
obs_data_release(settings);
|
||||
|
||||
propertiesView = new OBSPropertiesView(settings, script,
|
||||
(PropertiesReloadCallback)obs_script_get_properties,
|
||||
(PropertiesUpdateCallback)obs_script_update);
|
||||
propertiesView = new OBSPropertiesView(
|
||||
settings, script,
|
||||
(PropertiesReloadCallback)obs_script_get_properties,
|
||||
(PropertiesUpdateCallback)obs_script_update);
|
||||
ui->propertiesLayout->addWidget(propertiesView);
|
||||
ui->description->setText(obs_script_get_description(script));
|
||||
}
|
||||
|
|
@ -457,8 +457,7 @@ static void obs_event(enum obs_frontend_event event, void *)
|
|||
|
||||
static void load_script_data(obs_data_t *load_data, bool, void *)
|
||||
{
|
||||
obs_data_array_t *array = obs_data_get_array(load_data,
|
||||
"scripts-tool");
|
||||
obs_data_array_t *array = obs_data_get_array(load_data, "scripts-tool");
|
||||
|
||||
delete scriptData;
|
||||
scriptData = new ScriptData;
|
||||
|
|
@ -509,21 +508,19 @@ static void save_script_data(obs_data_t *save_data, bool saving, void *)
|
|||
}
|
||||
|
||||
static void script_log(void *, obs_script_t *script, int log_level,
|
||||
const char *message)
|
||||
const char *message)
|
||||
{
|
||||
QString qmsg;
|
||||
|
||||
if (script) {
|
||||
qmsg = QStringLiteral("[%1] %2").arg(
|
||||
obs_script_get_file(script),
|
||||
message);
|
||||
obs_script_get_file(script), message);
|
||||
} else {
|
||||
qmsg = QStringLiteral("[Unknown Script] %1").arg(message);
|
||||
}
|
||||
|
||||
QMetaObject::invokeMethod(scriptLogWindow, "AddLogMsg",
|
||||
Q_ARG(int, log_level),
|
||||
Q_ARG(QString, qmsg));
|
||||
Q_ARG(int, log_level), Q_ARG(QString, qmsg));
|
||||
}
|
||||
|
||||
extern "C" void InitScripts()
|
||||
|
|
@ -533,13 +530,13 @@ extern "C" void InitScripts()
|
|||
obs_scripting_load();
|
||||
obs_scripting_set_log_callback(script_log, nullptr);
|
||||
|
||||
QAction *action = (QAction*)obs_frontend_add_tools_menu_qaction(
|
||||
obs_module_text("Scripts"));
|
||||
QAction *action = (QAction *)obs_frontend_add_tools_menu_qaction(
|
||||
obs_module_text("Scripts"));
|
||||
|
||||
#if PYTHON_UI
|
||||
config_t *config = obs_frontend_get_global_config();
|
||||
const char *python_path = config_get_string(config, "Python",
|
||||
"Path" ARCH_NAME);
|
||||
const char *python_path =
|
||||
config_get_string(config, "Python", "Path" ARCH_NAME);
|
||||
|
||||
if (!obs_scripting_python_loaded() && python_path && *python_path)
|
||||
obs_scripting_load_python(python_path);
|
||||
|
|
@ -547,8 +544,7 @@ extern "C" void InitScripts()
|
|||
|
||||
scriptData = new ScriptData;
|
||||
|
||||
auto cb = [] ()
|
||||
{
|
||||
auto cb = []() {
|
||||
obs_frontend_push_ui_translation(obs_module_get_string);
|
||||
|
||||
if (!scriptsWindow) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue