diff --git a/README.md b/README.md
index 4c9a5fe80..e72cdffc1 100644
--- a/README.md
+++ b/README.md
@@ -2,7 +2,7 @@
This is the official client used, it is a derivative of [Attorney-Online-Client-Remake](https://github.com/AttorneyOnline/AO2-Client).
## Qt
-This project uses Qt 5.15.2 (5.12.8 for Linux), which is licensed under the [GNU Lesser General Public License](https://www.gnu.org/licenses/lgpl-3.0.txt) with [certain licensing restrictions and exceptions](https://www.qt.io/qt-licensing-terms/). To comply with licensing requirements for static linking, object code is available if you would like to relink with an alternative version of Qt, and the source code for Qt may be found at https://github.com/qt/qtbase, http://code.qt.io/cgit/, or at https://qt.io.
+This project uses Qt 5.15.2 (5.12.8 for Linux, and 5.15.13 for MacOS via [Homebrew](https://brew.sh/)), which is licensed under the [GNU Lesser General Public License](https://www.gnu.org/licenses/lgpl-3.0.txt) with [certain licensing restrictions and exceptions](https://www.qt.io/qt-licensing-terms/). To comply with licensing requirements for static linking, object code is available if you would like to relink with an alternative version of Qt, and the source code for Qt may be found at https://github.com/qt/qtbase, http://code.qt.io/cgit/, or at https://qt.io.
Copyright (C) 2022 The Qt Company Ltd.
@@ -10,3 +10,24 @@ Copyright (C) 2022 The Qt Company Ltd.
This project uses [BASS shared library](http://www.un4seen.com/).
Copyright (c) 1999-2022 Un4seen Developments Ltd. All rights reserved.
+
+## Discord-RPC
+This project uses the deprecated [discord-rpc library](https://github.com/discord/discord-rpc).
+
+## VLC-Qt
+This project uses [VLC-Qt 1.1.0](https://vlc-qt.tano.si/) in order to play videos with bundled codecs. You may find the source code and the binaries here: https://github.com/vlc-qt/vlc-qt
+
+Copyright (C) 2010-2016 Tadej Novak
+
+## Recommended Compilers in QtCreator
+
+For development work on Windows to make 64-bit binaries, please use the MSVC2019 compiler. You will need to install the MSVC2019 Build Tools from the following website:
+https://learn.microsoft.com/en-au/visualstudio/releases/2019/history
+
+For development work on Windows to make 32-bit binaries, please use the MingW32-bit compiler.
+
+For development work on the Mac to make 64-bit Silicon binaries, please use Clang (C/C++ arm 64bit).
+
+For development work on the Mac to make 64-bit Intel binaries, please use Apple Clang (x64_64).
+
+NOTE: If you get a `windeployqt` or `macdeployqt` not found error, you need to manually go to "QtCreator > Projects > Edit Build Configuration (Release) > Build Environment > Edit Path" and add the folder containing the correct version of the deployqt script (be sure to use the one matching the compiler and Qt version). For example, on Windows if using the default installation path, the path for MSVC2019 64-bit is `C:\Qt\5.15.2\msvc2019_64\bin`
diff --git a/dronline-client.pro b/dronline-client.pro
index d66e7e0f9..99f2b032d 100644
--- a/dronline-client.pro
+++ b/dronline-client.pro
@@ -7,9 +7,26 @@ VERSION = 2.0.0
TARGET = dro-client
RC_ICONS = icon.ico
+TARGETPLATFORM = unknown
-INCLUDEPATH += $$PWD/include $$PWD/src $$PWD/3rd
-DEPENDPATH += $$PWD/include $$PWD/src $$PWD/3rd
+INCLUDEPATH += $$PWD/include $$PWD/src
+DEPENDPATH += $$PWD/include $$PWD/src
+
+win32 {
+ !contains(QMAKE_HOST.arch, x86_64) {
+ TARGETPLATFORM = win32
+ } else {
+ TARGETPLATFORM = win64
+ }
+}
+macx {
+ TARGETPLATFORM = macx64
+}
+
+message("TARGETPLATFORM = $$TARGETPLATFORM")
+
+INCLUDEPATH += $$PWD/3rd/$$TARGETPLATFORM
+DEPENDPATH += $$PWD/3rd/$$TARGETPLATFORM
HEADERS += \
src/aoapplication.h \
@@ -281,14 +298,6 @@ SOURCES += \
src/utils.cpp \
src/version.cpp
-# 1. You need to get BASS and put the x86 bass DLL/headers in the project root folder
-# AND the compilation output folder. If you want a static link, you'll probably
-# need the .lib file too. MinGW-GCC is really finicky finding BASS, it seems.
-# 2. You need to compile the Discord Rich Presence SDK separately and add the lib/headers
-# in the same way as BASS. Discord RPC uses CMake, which does not play nicely with
-# QMake, so this step must be manual.
-LIBS += -L$$PWD/3rd -lbass -lbassopus -ldiscord-rpc
-
RESOURCES += \
res.qrc
@@ -304,3 +313,39 @@ FORMS += \
# Mac stuff
QMAKE_MACOSX_DEPLOYMENT_TARGET = 10.13
ICON = icon.icns
+
+# 1. You need to get BASS and put the x86 bass DLL/headers in the project root folder
+# AND the compilation output folder. If you want a static link, you'll probably
+# need the .lib file too. MinGW-GCC is really finicky finding BASS, it seems.
+# 2. You need to compile the Discord Rich Presence SDK separately and add the lib/headers
+# in the same way as BASS. Discord RPC uses CMake, which does not play nicely with
+# QMake, so this step must be manual.
+# 3. You need to get VLC-Qt and place them in the 3rd folder too. Be sure to include the
+# plugins folder too which contains all the codecs that VLC uses. If you're compiling
+# on MacOS, copy the framework folders directly
+win32 {
+ LIBS += -L$$PWD/3rd/$$TARGETPLATFORM -lbass -lbassopus -ldiscord-rpc -lVLCQtCore -lVLCQtWidgets
+}
+macx {
+ LIBS += -L$$PWD/3rd/$$TARGETPLATFORM -lbass -lbassopus -ldiscord-rpc
+ LIBS += -F$$PWD/3rd/$$TARGETPLATFORM -framework VLCQtCore -framework VLCQtWidgets
+ QMAKE_APPLE_DEVICE_ARCHS = x86_64
+}
+
+CONFIG( debug, debug|release ) {
+ # debug, copy 3rd party libraries only for windows
+ win32 {
+ QMAKE_POST_LINK += $$quote(python3 $$PWD/post-build-script.py $$TARGETPLATFORM$$escape_expand(\n\t))
+ }
+} else {
+ # release, copy 3rd party libraries always
+ QMAKE_POST_LINK += $$quote(python3 $$PWD/post-build-script.py $$TARGETPLATFORM$$escape_expand(\n\t))
+
+ # Run deployqt to copy Qt libraries
+ win32 {
+ QMAKE_POST_LINK += windeployqt $$shell_quote($$shell_path($${OUT_PWD}/release/$${TARGET}.exe))$$escape_expand(\n\t)
+ }
+ macx {
+ QMAKE_POST_LINK += macdeployqt $$shell_quote($$shell_path($${OUT_PWD}/$${TARGET}.app)) -dmg -always-overwrite$$escape_expand(\n\t)
+ }
+}
diff --git a/post-build-script.py b/post-build-script.py
new file mode 100644
index 000000000..ccb7dea4d
--- /dev/null
+++ b/post-build-script.py
@@ -0,0 +1,53 @@
+import os
+import sys
+import glob
+import shutil
+
+if len(sys.argv) != 2:
+ print('This script takes exactly one argument: win32, win64 or macx64')
+ exit(1)
+
+libs_dir = sys.argv[1]
+pro_dir = os.path.dirname(os.path.realpath(__file__))
+build_dir = os.getcwd()
+
+# Check what platform the build directory is
+if glob.glob(build_dir + '/release/*.exe'):
+ platform = 'win'
+ type_dir = 'release'
+ print('Windows release build detected. Proceeding to copy Windows libraries')
+elif glob.glob(build_dir + '/debug/*.exe'):
+ platform = 'win'
+ type_dir = 'debug'
+ print('Windows debug build detected. Proceeding to copy Windows libraries')
+elif glob.glob(build_dir + '/*.app'):
+ platform = 'mac'
+ macapp_dir = glob.glob(build_dir + '/*.app')[0]
+ print('MacOS build detected. Proceeding to copy MacOS libraries')
+else:
+ platform = 'unknown'
+ print('Unable to detect platform of build binary.')
+ exit(1)
+
+# Copies all the DLLs over
+if platform == 'win':
+ for file in glob.glob(pro_dir + '/3rd/' + libs_dir + '/*.dll'):
+ print('Copying', file)
+ shutil.copy2(file, build_dir + '/' + type_dir + '/')
+ for file in glob.glob(pro_dir + '/3rd/' + libs_dir + '/*.lib'):
+ print('Copying', file)
+ shutil.copy2(file, build_dir + '/' + type_dir + '/')
+ print('Copying directory ' + pro_dir + '/3rd/' + libs_dir + '/plugins')
+ shutil.copytree(pro_dir + '/3rd/' + libs_dir + '/plugins', build_dir + '/' + type_dir + '/plugins', dirs_exist_ok=True, symlinks=True, ignore_dangling_symlinks=True)
+elif platform == 'mac':
+ if not os.path.isdir(macapp_dir + '/Contents/Frameworks/'):
+ os.makedirs(macapp_dir + '/Contents/Frameworks/')
+ for file in glob.glob(pro_dir + '/3rd/' + libs_dir + '/*.dylib'):
+ print('Copying', file)
+ shutil.copy2(file, macapp_dir + '/Contents/Frameworks/')
+ for file in glob.glob(pro_dir + '/3rd/' + libs_dir + '/*.framework'):
+ print('Copying', file)
+ dest_dir = macapp_dir + '/Contents/Frameworks/' + os.path.basename(file)
+ if os.path.isdir(dest_dir):
+ shutil.rmtree(dest_dir)
+ shutil.copytree(file, dest_dir, dirs_exist_ok=True, symlinks=True, ignore_dangling_symlinks=True)
diff --git a/res/ui/config_panel.ui b/res/ui/config_panel.ui
index 522052b1d..8e743e48f 100644
--- a/res/ui/config_panel.ui
+++ b/res/ui/config_panel.ui
@@ -7,7 +7,7 @@
0
0
890
- 544
+ 572
@@ -62,7 +62,7 @@
- 3
+ 0
@@ -116,6 +116,32 @@
+ -
+
+
+
+ 0
+ 60
+
+
+
+ Video
+
+
+
+
+ 10
+ 30
+ 691
+ 20
+
+
+
+ Use libvlc to play videos (better support for MacOS)
+
+
+
+
-
@@ -1628,8 +1654,8 @@
10
190
- 247
- 26
+ 262
+ 32
diff --git a/src/aoapplication.h b/src/aoapplication.h
index a48a36fef..e4e243d9a 100644
--- a/src/aoapplication.h
+++ b/src/aoapplication.h
@@ -42,6 +42,8 @@ class AOApplication : public QApplication
AOApplication(int &argc, char **argv);
~AOApplication();
+ AOConfig *ao_config = nullptr;
+
int get_client_id() const;
void set_client_id(int id);
@@ -219,7 +221,6 @@ public slots:
void server_status_changed(ServerStatus);
private:
- AOConfig *ao_config = nullptr;
AOConfigPanel *ao_config_panel = nullptr;
DRDiscord *dr_discord = nullptr;
diff --git a/src/aoconfig.cpp b/src/aoconfig.cpp
index 3f31a021a..faa28f5c1 100644
--- a/src/aoconfig.cpp
+++ b/src/aoconfig.cpp
@@ -118,6 +118,9 @@ private slots:
int fade_duration;
bool blank_blips;
+ // video
+ bool is_video_backend_vlc;
+
// audio sync
DRAudioEngine *audio_engine = nullptr;
};
@@ -240,6 +243,26 @@ void AOConfigPrivate::load_file()
SceneManager::get().setFadeDuration(fade_duration);
blank_blips = cfg.value("blank_blips").toBool();
+#ifdef QT_DEBUG
+ #ifdef Q_CC_MSVC
+ is_video_backend_vlc = false;
+ qWarning() << "NOTE: libvlc automatically turned off for MSVC debug mode because it VLC-Qt seems to crash with it.";
+ #else
+ #ifdef Q_OS_MAC
+ is_video_backend_vlc = cfg.value("video_backend", "vlc").toString() == "vlc";
+ #else
+ is_video_backend_vlc = cfg.value("video_backend", "qt").toString() == "vlc";
+ #endif
+ #endif
+#else
+ // video
+ #ifdef Q_OS_MAC
+ is_video_backend_vlc = cfg.value("video_backend", "vlc").toString() == "vlc";
+ #else
+ is_video_backend_vlc = cfg.value("video_backend", "qt").toString() == "vlc";
+ #endif
+#endif
+
// audio update
audio_engine->set_volume(master_volume);
audio_engine->get_family(DRAudio::Family::FSystem)->set_volume(system_volume);
@@ -351,6 +374,9 @@ void AOConfigPrivate::save_file()
cfg.setValue("fade_duration", fade_duration);
cfg.setValue("blank_blips", blank_blips);
+ // video
+ cfg.setValue("video_backend", is_video_backend_vlc ? "vlc" : "qt");
+
cfg.remove("character_ini");
{ // ini swap
cfg.beginGroup("character_ini");
@@ -751,6 +777,11 @@ int AOConfig::fade_duration() const
return d->fade_duration;
}
+bool AOConfig::video_backend_vlc() const
+{
+ return d->is_video_backend_vlc;
+}
+
void AOConfig::load_file()
{
d->load_file();
@@ -1252,5 +1283,13 @@ void AOConfig::setFadeDuration(int duration)
d->invoke_signal("fade_duration_changed", Q_ARG(int, duration));
}
+void AOConfig::set_video_backend_vlc(bool p_video_backend_vlc)
+{
+ if (d->is_video_backend_vlc == p_video_backend_vlc)
+ return;
+ d->is_video_backend_vlc = p_video_backend_vlc;
+ d->invoke_signal("fade_duration_changed", Q_ARG(bool, d->is_video_backend_vlc));
+}
+
// moc
#include "aoconfig.moc"
diff --git a/src/aoconfig.h b/src/aoconfig.h
index f5e6918b9..2236783f0 100644
--- a/src/aoconfig.h
+++ b/src/aoconfig.h
@@ -2,6 +2,7 @@
#define AOCONFIG_H
#include "datatypes.h"
+#include "aoapplication.h"
#include
@@ -15,6 +16,8 @@ class AOConfig : public QObject
AOConfig(QObject *p_parent = nullptr);
~AOConfig();
+ AOApplication* ao_app = nullptr;
+
// generic getters
QString get_string(QString p_name, QString p_default = nullptr) const;
bool get_bool(QString p_name, bool p_default = false) const;
@@ -85,6 +88,9 @@ class AOConfig : public QObject
double theme_resize() const;
int fade_duration() const;
+ // video
+ bool video_backend_vlc() const;
+
// io
public slots:
void load_file();
@@ -155,6 +161,9 @@ public slots:
void setThemeResize(double resize);
void setFadeDuration(int duration);
+ // video
+ void set_video_backend_vlc(bool p_video_backend_vlc);
+
// signals
signals:
// meta
@@ -226,6 +235,9 @@ public slots:
void punctuation_delay_changed(int);
void blank_blips_changed(bool);
+ // video
+ void video_backend_vlc_changed(bool);
+
//Theme
void theme_resize_changed(double);
void fade_duration_changed(int);
diff --git a/src/aoconfigpanel.cpp b/src/aoconfigpanel.cpp
index 05879ebea..ca70fee3a 100644
--- a/src/aoconfigpanel.cpp
+++ b/src/aoconfigpanel.cpp
@@ -175,6 +175,15 @@ AOConfigPanel::AOConfigPanel(AOApplication *p_ao_app, QWidget *p_parent)
{ui_blip, ui_blip_value}
};
+ // video
+ ui_video_backend_vlc = AO_GUI_WIDGET(QCheckBox, "video_backend_vlc");
+#ifdef QT_DEBUG
+ #ifdef Q_CC_MSVC
+ ui_video_backend_vlc->setChecked(false);
+ //ui_video_backend_vlc->setDisabled(true);
+ #endif
+#endif
+
// about
ui_about = AO_GUI_WIDGET(QLabel, "about_label");
@@ -255,6 +264,9 @@ AOConfigPanel::AOConfigPanel(AOApplication *p_ao_app, QWidget *p_parent)
connect(m_engine, SIGNAL(device_list_changed(QVector)), this, SLOT(on_audio_device_list_changed(QVector)));
connect(m_engine, SIGNAL(favorite_device_changed(DRAudioDevice)), this, SLOT(on_favorite_audio_device_changed(DRAudioDevice)));
+ // video
+ connect(m_config, SIGNAL(video_backend_vlc_changed(bool)), ui_video_backend_vlc, SLOT(setChecked(bool)));
+
// meta
connect(ui_close, SIGNAL(clicked()), this, SLOT(close()));
connect(ui_save, SIGNAL(clicked()), m_config, SLOT(save_file()));
@@ -333,6 +345,8 @@ AOConfigPanel::AOConfigPanel(AOApplication *p_ao_app, QWidget *p_parent)
connect(ui_punctuation_delay, SIGNAL(valueChanged(int)), m_config, SLOT(set_punctuation_delay(int)));
connect(ui_blank_blips, SIGNAL(toggled(bool)), m_config, SLOT(set_blank_blips(bool)));
+ connect(ui_video_backend_vlc, &QAbstractButton::toggled, m_config, &AOConfig::set_video_backend_vlc);
+
connect(ui_theme_resize, SIGNAL(valueChanged(double)), m_config, SLOT(setThemeResize(double)));
connect(ui_fade_duration, SIGNAL(valueChanged(int)), m_config, SLOT(setFadeDuration(int)));
@@ -427,6 +441,8 @@ AOConfigPanel::AOConfigPanel(AOApplication *p_ao_app, QWidget *p_parent)
ui_punctuation_delay->setValue(m_config->punctuation_delay());
ui_blank_blips->setChecked(m_config->blank_blips_enabled());
+ ui_video_backend_vlc->setChecked(m_config->video_backend_vlc());
+
ui_theme_resize->setValue(m_config->theme_resize());
ui_fade_duration->setValue(m_config->fade_duration());
diff --git a/src/aoconfigpanel.h b/src/aoconfigpanel.h
index 21f7a6fb7..a2fa8c63b 100644
--- a/src/aoconfigpanel.h
+++ b/src/aoconfigpanel.h
@@ -203,6 +203,9 @@ private slots:
QLabel *ui_blip_value = nullptr;
QPushButton *ui_reload_audiotracks = nullptr;
+ // video
+ QCheckBox *ui_video_backend_vlc = nullptr;
+
// about
QLabel *ui_about = nullptr;
diff --git a/src/courtroom.cpp b/src/courtroom.cpp
index 77458cfa6..653a0ac28 100644
--- a/src/courtroom.cpp
+++ b/src/courtroom.cpp
@@ -75,6 +75,7 @@ Courtroom::Courtroom(AOApplication *p_ao_app, QWidget *parent)
{
ao_app = p_ao_app;
ao_config = new AOConfig(this);
+ ao_app->m_courtroom = this;
m_preloader_sync = new mk2::SpriteReaderSynchronizer(this);
m_preloader_sync->set_threshold(ao_config->caching_threshold());
@@ -102,7 +103,7 @@ Courtroom::Courtroom(AOApplication *p_ao_app, QWidget *parent)
set_char_select();
load_audiotracks();
reset_viewport();
- PairManager::get().SetUserPair(-1, 480);
+ PairManager::get().SetUserPair(-1, 480);
}
Courtroom::~Courtroom()
@@ -817,6 +818,13 @@ bool Courtroom::is_spectating()
return m_chr_id == SpectatorId;
}
+QRect Courtroom::get_video_rect()
+{
+ if (ui_viewport == nullptr)
+ return QRect();
+ return ui_viewport->geometry();
+}
+
void Courtroom::on_showname_placeholder_changed(QString p_showname_placeholder)
{
const QString l_showname(p_showname_placeholder.trimmed().isEmpty() ? LocalizationManager::get().getLocalizationText("TEXTBOX_SHOWNAME") : p_showname_placeholder);
diff --git a/src/courtroom.h b/src/courtroom.h
index e61a38f66..22beeb0a5 100644
--- a/src/courtroom.h
+++ b/src/courtroom.h
@@ -302,6 +302,7 @@ private slots:
public:
AOConfig *ao_config = nullptr;
bool is_spectating();
+ QRect get_video_rect();
private:
bool m_first_theme_loading = true;
diff --git a/src/draudiostream.cpp b/src/draudiostream.cpp
index 2466a55fc..8c650120f 100644
--- a/src/draudiostream.cpp
+++ b/src/draudiostream.cpp
@@ -226,7 +226,11 @@ bool DRAudioStream::ensure_init()
if(!m_url.isEmpty())
{
+#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 13)
+ l_hstream = BASS_StreamCreateURL(reinterpret_cast(m_url.utf16()), 0, 0, nullptr, nullptr);
+#else
l_hstream = BASS_StreamCreateURL(reinterpret_cast(m_url.utf16()), 0, 0, nullptr, nullptr);
+#endif
}
else if (m_filename.isEmpty())
{
diff --git a/src/drmediatester.cpp b/src/drmediatester.cpp
index bb6569bb4..605f56177 100644
--- a/src/drmediatester.cpp
+++ b/src/drmediatester.cpp
@@ -1,4 +1,6 @@
#include "drmediatester.h"
+#include "aoapplication.h"
+#include "aoconfig.h"
#include
@@ -7,11 +9,25 @@
DRMediaTester::DRMediaTester(QObject *parent)
: QObject(parent)
{
- m_player.setMuted(true);
+ AOApplication* ap_app = static_cast(parent);
- connect(&m_player, SIGNAL(mediaStatusChanged(QMediaPlayer::MediaStatus)), this, SLOT(p_check_status(QMediaPlayer::MediaStatus)));
+ if (ap_app->ao_config->video_backend_vlc())
+ {
+ _vlcInstance = new VlcInstance(VlcCommon::args(), this);
+ _vlcPlayer = new VlcMediaPlayer(_vlcInstance);
+
+ connect(_vlcPlayer, SIGNAL(error()), this, SLOT(p_vlc_error()));
+ _vlcMedia = new VlcMedia(QUrl("qrc:/data/sample.avi").toLocalFile(), true, _vlcInstance);
+ _vlcPlayer->open(_vlcMedia);
+ }
+ else
+ {
+ m_player.setMuted(true);
+
+ connect(&m_player, SIGNAL(mediaStatusChanged(QMediaPlayer::MediaStatus)), this, SLOT(p_check_status(QMediaPlayer::MediaStatus)));
- m_player.setMedia(QUrl("qrc:/data/sample.avi"));
+ m_player.setMedia(QUrl("qrc:/data/sample.avi"));
+ }
}
DRMediaTester::~DRMediaTester()
@@ -24,7 +40,8 @@ void DRMediaTester::p_check_status(QMediaPlayer::MediaStatus p_status)
case QMediaPlayer::InvalidMedia:
call_warning("Your operating system appears to not currently support video playback. The video "
"playback will not work properly.
In order for the feature to function properly, you "
- "will need to install additional codecs.
For more information visit "
+ "will need to install additional codecs or use libvlc in settings.
"
+ "For more information visit "
"https://www.danganronpaonline.com");
emit done();
break;
@@ -37,3 +54,9 @@ void DRMediaTester::p_check_status(QMediaPlayer::MediaStatus p_status)
break;
}
}
+
+void DRMediaTester::p_vlc_error()
+{
+ call_warning("libVLC has failed to initialize");
+ emit done();
+}
diff --git a/src/drmediatester.h b/src/drmediatester.h
index c8ee9bc3c..03331397c 100644
--- a/src/drmediatester.h
+++ b/src/drmediatester.h
@@ -2,6 +2,10 @@
#include
#include
+#include
+#include
+#include
+#include
class DRMediaTester : public QObject
{
@@ -16,7 +20,12 @@ class DRMediaTester : public QObject
private:
QMediaPlayer m_player;
+ VlcInstance *_vlcInstance;
+ VlcMedia *_vlcMedia;
+ VlcMediaPlayer *_vlcPlayer;
+
private slots:
void p_check_status(QMediaPlayer::MediaStatus p_status);
+ void p_vlc_error();
};
diff --git a/src/lobby.cpp b/src/lobby.cpp
index b083f894b..d3dbd7c53 100644
--- a/src/lobby.cpp
+++ b/src/lobby.cpp
@@ -41,7 +41,6 @@
#include
-
Lobby::Lobby(AOApplication *p_ao_app)
: QMainWindow()
{
diff --git a/src/mk2/graphicsvideoscreen.cpp b/src/mk2/graphicsvideoscreen.cpp
index 4a4b6d781..1ff01b637 100644
--- a/src/mk2/graphicsvideoscreen.cpp
+++ b/src/mk2/graphicsvideoscreen.cpp
@@ -18,6 +18,7 @@
**
**************************************************************************/
#include "graphicsvideoscreen.h"
+#include "courtroom.h"
#include
#include
@@ -25,6 +26,9 @@
#include
#include
+#include
+#include
+
DRVideoScreen::DRVideoScreen(AOApplication *ao_app, QGraphicsItem *parent)
: QGraphicsVideoItem(parent)
, ao_app(ao_app)
@@ -37,7 +41,14 @@ DRVideoScreen::DRVideoScreen(AOApplication *ao_app, QGraphicsItem *parent)
, m_player(new QMediaPlayer(this, QMediaPlayer::LowLatency))
{
setAspectRatioMode(Qt::KeepAspectRatioByExpanding);
+ _widget = nullptr;
+
+ // Setup libvlc
+ _vlcInstance = nullptr;
+ vlc_initialized = false;
+ initialize_vlc();
+ // Setup Qt Media Player
m_player->setVideoOutput(this);
connect(m_player, SIGNAL(videoAvailableChanged(bool)), this, SLOT(update_video_availability(bool)));
@@ -57,19 +68,69 @@ DRVideoScreen::DRVideoScreen(AOApplication *ao_app, QGraphicsItem *parent)
DRVideoScreen::~DRVideoScreen()
{}
-QString DRVideoScreen::get_file_name() const
+float init_delay = 1000;
+bool DRVideoScreen::initialize_vlc()
{
- return m_file_name;
+ if (_vlcInstance != nullptr)
+ return vlc_initialized;
+ if (!ao_app->ao_config->video_backend_vlc())
+ return false;
+
+ // qDebug() << "//// INTIALIZING VLC for " << this;
+ _vlcInstance = new VlcInstance(VlcCommon::args(), this);
+ _vlcPlayer = new VlcMediaPlayer(_vlcInstance);
+ _vlcWidget = new VlcWidgetVideo(_widget);
+ _vlcWidget->setMediaPlayer(_vlcPlayer);
+ _vlcPlayer->setVideoWidget(_vlcWidget);
+
+ connect(_vlcPlayer, SIGNAL(stateChanged()), this, SLOT(vlc_stateChanged()));
+ //connect(_vlcPlayer, SIGNAL(mediaChanged()), this, SLOT(vlc_mediaChanged(libvlc_media_t*)));
+
+ QTimer::singleShot(init_delay, this, &DRVideoScreen::set_vlc_initialized);
+ return false;
}
-void DRVideoScreen::set_file_name(QString p_file_name)
+void DRVideoScreen::set_vlc_initialized()
+{
+ vlc_initialized = true;
+ // qDebug() << "//// VLC INITIALIZED DONE for " << this;
+}
+
+void DRVideoScreen::set_video_parent(QWidget* parent)
{
- if (m_file_name == p_file_name)
+ _widget = parent;
+ if (!initialize_vlc())
{
return;
}
+ if (_widget != nullptr)
+ {
+ _vlcWidget->setParent(_widget);
+ _vlcWidget->setGeometry(_widget->rect());
+ }
+ else
+ {
+ if (ao_app->m_courtroom->get_video_rect() != QRect())
+ {
+ _vlcWidget->setParent(ao_app->m_courtroom);
+ _vlcWidget->setGeometry(ao_app->m_courtroom->get_video_rect());
+ }
+ }
+}
+
+void DRVideoScreen::resized()
+{
+ set_video_parent(_widget);
+}
+
+QString DRVideoScreen::get_file_name() const
+{
+ return m_file_name;
+}
+
+void DRVideoScreen::set_file_name(QString p_file_name)
+{
stop();
- qInfo() << "loading media file" << p_file_name;
m_scanned = false;
m_video_available = false;
m_file_name = p_file_name;
@@ -77,7 +138,24 @@ void DRVideoScreen::set_file_name(QString p_file_name)
{
m_scanned = true;
}
- m_player->setMedia(QUrl::fromLocalFile(m_file_name));
+ if (ao_app->ao_config->video_backend_vlc())
+ {
+ if (!initialize_vlc())
+ {
+ QTimer::singleShot(init_delay, this, [p_file_name, this] () {
+ DRVideoScreen::set_file_name(p_file_name);
+ });
+ return;
+ }
+ qInfo() << "loading media file" << p_file_name << " for " << this;
+ _vlcMedia = new VlcMedia(m_file_name, true, _vlcInstance);
+ _vlcPlayer->open(_vlcMedia);
+ }
+ else
+ {
+ qInfo() << "loading media file" << p_file_name << " for " << this;
+ m_player->setMedia(QUrl::fromLocalFile(m_file_name));
+ }
}
void DRVideoScreen::play_character_video(QString p_character, QString p_video)
@@ -119,10 +197,61 @@ void DRVideoScreen::play()
void DRVideoScreen::stop()
{
m_running = false;
+
if (m_player->state() != QMediaPlayer::StoppedState)
{
m_player->stop();
}
+ if (ao_app->ao_config->video_backend_vlc())
+ {
+ if (!initialize_vlc())
+ {
+ return;
+ }
+ if ( _vlcPlayer->state() == Vlc::State::Playing)
+ {
+ _vlcPlayer->stop();
+ }
+ }
+}
+
+void DRVideoScreen::vlc_stateChanged()
+{
+ if (m_vlc_state == _vlcPlayer->state())
+ {
+ return;
+ }
+ // qDebug() << "//// STATE: " << _vlcPlayer->state() << " VLCMEDIA: " << _vlcMedia;
+ m_vlc_state = _vlcPlayer->state();
+ switch (m_vlc_state)
+ {
+ case Vlc::State::Error:
+ m_scanned = true;
+ qWarning() << "error: media file is invalid:" << m_file_name;
+ finish_playback();
+ break;
+
+ case Vlc::State::Playing:
+ emit started();
+ start_playback();
+ break;
+
+ case Vlc::State::Ended:
+ finish_playback();
+ _vlcMedia->deleteLater();
+ _vlcMedia = nullptr;
+ _vlcWidget->hide();
+ break;
+
+ default:
+ break;
+ }
+}
+
+void DRVideoScreen::vlc_mediaChanged(libvlc_media_t* media)
+{
+ //qDebug() << "//// STATE: " << _vlcPlayer->state() << " MEDIA: " << media << " VLCMEDIA: " << _vlcMedia;
+ // Currently this signal is not being called. Ignored for now.
}
void DRVideoScreen::update_video_availability(bool p_video_available)
@@ -186,11 +315,29 @@ void DRVideoScreen::check_state(QMediaPlayer::State p_state)
void DRVideoScreen::start_playback()
{
- if (m_player->state() == QMediaPlayer::StoppedState)
+ if (ao_app->ao_config->video_backend_vlc())
+ {
+ if (!initialize_vlc())
+ {
+ QTimer::singleShot(init_delay, this, &DRVideoScreen::start_playback);
+ return;
+ }
+ _vlcPlayer->setPosition(0);
+ update_volume();
+ // qInfo() << "/// start playback for " << this << " at " << ao_app->m_courtroom->get_video_rect() << " on parent " << _vlcWidget->parentWidget();
+ set_video_parent(_widget);
+ _vlcWidget->show();
+ _vlcWidget->activateWindow();
+ _vlcWidget->raise();
+ }
+ else
{
- update_audio_output();
+ if (m_player->state() == QMediaPlayer::StoppedState)
+ {
+ update_audio_output();
- m_player->play();
+ m_player->play();
+ }
}
}
@@ -250,9 +397,22 @@ void DRVideoScreen::update_volume()
l_volume = 0;
}
- if (m_player->volume() == l_volume)
+ if (m_player->volume() != l_volume)
{
- return;
+ m_player->setVolume(l_volume);
+ }
+
+ if (ao_app->ao_config->video_backend_vlc())
+ {
+ if (!initialize_vlc())
+ {
+ return;
+ }
+ // improve audio volume scaling for vlc since it's different from QMediaPlayer
+ int transformed_volume = sqrt(sqrt(l_volume) * 10) * 10;
+ if (_vlcPlayer->audio()->volume() != transformed_volume)
+ {
+ _vlcPlayer->audio()->setVolume(transformed_volume);
+ }
}
- m_player->setVolume(l_volume);
}
diff --git a/src/mk2/graphicsvideoscreen.h b/src/mk2/graphicsvideoscreen.h
index af9f7ff13..6028672c0 100644
--- a/src/mk2/graphicsvideoscreen.h
+++ b/src/mk2/graphicsvideoscreen.h
@@ -26,6 +26,14 @@
#include
#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
class DRVideoScreen : public QGraphicsVideoItem
{
@@ -35,7 +43,9 @@ class DRVideoScreen : public QGraphicsVideoItem
DRVideoScreen(AOApplication *ao_app, QGraphicsItem *parent = nullptr);
~DRVideoScreen();
+ void set_video_parent(QWidget *parent);
QString get_file_name() const;
+ QWidget *_widget;
public slots:
void set_file_name(QString file_name);
@@ -46,6 +56,8 @@ public slots:
void stop();
+ void resized();
+
signals:
void started();
@@ -70,11 +82,29 @@ public slots:
QMediaPlayer *m_player;
+ VlcInstance *_vlcInstance;
+ VlcMedia *_vlcMedia;
+ VlcMediaPlayer *_vlcPlayer;
+ VlcWidgetVideo *_vlcWidget;
+
+ bool vlc_initialized;
+
void start_playback();
void finish_playback();
+ bool initialize_vlc();
+
+ void set_vlc_initialized();
+
+ Vlc::State m_vlc_state;
+
private slots:
+ // libvlc slots
+ void vlc_stateChanged();
+ void vlc_mediaChanged(libvlc_media_t* media);
+
+ // Qt Media Player slots
void update_video_availability(bool);
void check_status(QMediaPlayer::MediaStatus);
diff --git a/src/modules/widgets/droviewportwidget.cpp b/src/modules/widgets/droviewportwidget.cpp
index d1ef00489..5b164a9fc 100644
--- a/src/modules/widgets/droviewportwidget.cpp
+++ b/src/modules/widgets/droviewportwidget.cpp
@@ -32,6 +32,10 @@ void DROViewportWidget::ConstructViewport(ThemeSceneType t_scene)
this->scene()->addItem(m_VpShouts);
this->scene()->addItem(m_VpWtce);
+ // Video player needs special treatment since VLC doesn't use graphics scene
+ m_VpVideo->set_video_parent(this);
+ connect(this, SIGNAL(Resized()), m_VpVideo, SLOT(resized()));
+
m_VpBackground->start();
m_VpPlayer->start();
@@ -44,6 +48,8 @@ void DROViewportWidget::ConstructViewport(ThemeSceneType t_scene)
connect(m_VpPlayer, SIGNAL(done()), this, SLOT(OnPreanimDone()));
ConstructUserInterface();
+
+ this->installEventFilter(this);
}
void DROViewportWidget::ProcessIncomingMessage(ICMessageData *t_IncomingMessage)
@@ -253,3 +259,12 @@ void DROViewportWidget::OnPreanimDone()
m_VpPlayer->start();
}
}
+
+bool DROViewportWidget::eventFilter(QObject *obj, QEvent *event)
+{
+ // qDebug() << "//// EVENT " << event->type();
+ if (event->type() == QEvent::Resize)
+ emit Resized();
+ return QObject::eventFilter(obj, event);
+}
+
diff --git a/src/modules/widgets/droviewportwidget.h b/src/modules/widgets/droviewportwidget.h
index 4726e8f7c..c847f8f4a 100644
--- a/src/modules/widgets/droviewportwidget.h
+++ b/src/modules/widgets/droviewportwidget.h
@@ -45,14 +45,17 @@ class DROViewportWidget : public DRGraphicsView
signals:
void VideoDone();
void PreanimDone();
+ void Resized();
public slots:
void OnObjectionDone();
void OnVideoDone();
void OnPreanimDone();
-private:
+protected:
+ bool eventFilter(QObject *obj, QEvent *event) override;
+private:
DRGraphicsView *m_UserInterface = nullptr;
KeyframePlayer *m_ShoutsPlayer = nullptr;