Enable RLV for QT6 Video Window (#4609)

Overview widgets are enabled too for Windows and Linux, like they were when using VLC, macOS needs more testing.
This commit is contained in:
Ivor Hewitt
2025-03-07 11:17:19 +00:00
committed by GitHub
parent dd4987fbf0
commit b57e4386cb
3 changed files with 120 additions and 59 deletions

View File

@@ -84,6 +84,10 @@
#include "TrainDB.h"
#include "Library.h"
#if defined(GC_HAVE_VLC)||defined(GC_VIDEO_QT6) // RLV currently only support for VLC
#define USE_RLV
#endif
TrainSidebar::TrainSidebar(Context *context) : GcWindow(context), context(context),
bicycle(context)
{
@@ -149,7 +153,7 @@ TrainSidebar::TrainSidebar(Context *context) : GcWindow(context), context(contex
mediaTree->verticalScrollBar()->setStyle(cde);
#endif
#ifdef GC_HAVE_VLC // RLV currently only support for VLC
#ifdef USE_RLV
videosyncModel = trainDB->getVideoSyncModel();
vssortModel = new QSortFilterProxyModel(this);
@@ -186,7 +190,7 @@ TrainSidebar::TrainSidebar(Context *context) : GcWindow(context), context(contex
videosyncTree->verticalScrollBar()->setStyle(cdevideosync);
#endif
#endif //GC_HAVE_VLC
#endif //USE_RLV
#endif //GC_VIDEO_NONE
@@ -320,7 +324,7 @@ TrainSidebar::TrainSidebar(Context *context) : GcWindow(context), context(contex
mediaTree->setWhatsThis(helpMediaTree->getWhatsThisText(HelpWhatsThis::SideBarTrainView_Media));
trainSplitter->addWidget(mediaItem);
#ifdef GC_HAVE_VLC // RLV currently only support for VLC
#ifdef USE_RLV
videosyncItem = new GcSplitterItem(tr("VideoSync"), iconFromPNG(":images/sidebar/sync.png"), this);
QAction *moreVideoSyncAct = new QAction(iconFromPNG(":images/sidebar/extra.png"), tr("Menu"), this);
videosyncItem->addAction(moreVideoSyncAct);
@@ -329,7 +333,7 @@ TrainSidebar::TrainSidebar(Context *context) : GcWindow(context), context(contex
HelpWhatsThis *helpVideosyncTree = new HelpWhatsThis(videosyncTree);
videosyncTree->setWhatsThis(helpVideosyncTree->getWhatsThisText(HelpWhatsThis::SideBarTrainView_VideoSync));
trainSplitter->addWidget(videosyncItem);
#endif //GC_HAVE_VLC
#endif //USE_RLV
#endif //GC_VIDEO_NONE
trainSplitter->prepare(context->athlete->cyclist, "train");
@@ -354,11 +358,11 @@ TrainSidebar::TrainSidebar(Context *context) : GcWindow(context), context(contex
connect(mediaTree->selectionModel(), SIGNAL(selectionChanged(QItemSelection, QItemSelection)),
this, SLOT(mediaTreeWidgetSelectionChanged()));
connect(context, SIGNAL(selectMedia(QString)), this, SLOT(selectVideo(QString)));
#ifdef GC_HAVE_VLC // RLV currently only support for VLC
#ifdef USE_RLV
connect(videosyncTree->selectionModel(), SIGNAL(selectionChanged(QItemSelection, QItemSelection)),
this, SLOT(videosyncTreeWidgetSelectionChanged()));
connect(context, SIGNAL(selectVideoSync(QString)), this, SLOT(selectVideoSync(QString)));
#endif //GC_HAVE_VLC
#endif //USE_RLV
#endif //GC_VIDEO_NONE
connect(context, SIGNAL(configChanged(qint32)), this, SLOT(configChanged(qint32)));
connect(context, SIGNAL(selectWorkout(QString)), this, SLOT(selectWorkout(QString)));
@@ -438,7 +442,7 @@ TrainSidebar::~TrainSidebar
if (videoModel != nullptr) {
delete videoModel;
}
#ifdef GC_HAVE_VLC // RLV currently only support for VLC
#ifdef USE_RLV
if (videosyncModel != nullptr) {
delete videosyncModel;
}
@@ -459,7 +463,7 @@ TrainSidebar::refresh()
row = mediaTree->currentIndex().row();
QString videoPath = mediaTree->model()->data(mediaTree->model()->index(row, TdbVideoModelIdx::filepath)).toString();
#ifdef GC_HAVE_VLC // RLV currently only support for VLC
#ifdef USE_RLV
// refresh data
QAbstractTableModel *oldVideoModel = videoModel;
videoModel = trainDB->getVideoModel();
@@ -471,7 +475,7 @@ TrainSidebar::refresh()
// restore selection
selectVideo(videoPath);
#ifdef GC_HAVE_VLC // RLV currently only support for VLC
#ifdef USE_RLV
// remember selection
row = videosyncTree->currentIndex().row();
QString videosyncPath = videosyncTree->model()->data(videosyncTree->model()->index(row, TdbVideosyncModelIdx::filepath)).toString();
@@ -485,7 +489,7 @@ TrainSidebar::refresh()
// restore selection
selectVideoSync(videosyncPath);
#endif // GC_HAVE_VLC
#endif // USE_RLV
#endif // GC_VIDEO_NONE
@@ -695,7 +699,7 @@ TrainSidebar::configChanged(qint32 why)
setProperty("color", GColor(CTRAINPLOTBACKGROUND));
#if !defined GC_VIDEO_NONE
mediaTree->setStyleSheet(GCColor::stylesheet(true));
#ifdef GC_HAVE_VLC // RLV currently only support for VLC
#ifdef USE_RLV
videosyncTree->setStyleSheet(GCColor::stylesheet(true));
#endif
#endif
@@ -931,7 +935,7 @@ TrainSidebar::workoutTreeWidgetSelectionChanged()
QString workoutName = QFileInfo(filename).baseName();
mediaTree->setFocus();
mediaTree->keyboardSearch(workoutName);
#ifdef GC_HAVE_VLC // RLV currently only support for VLC
#ifdef USE_RLV
videosyncTree->setFocus();
videosyncTree->keyboardSearch(workoutName);
#endif
@@ -1302,7 +1306,7 @@ void TrainSidebar::Start() // when start button is pressed
#if !defined GC_VIDEO_NONE
mediaTree->setEnabled(false);
#ifdef GC_HAVE_VLC // RLV currently only support for VLC
#ifdef USE_RLV
videosyncTree->setEnabled(false);
#endif
#endif
@@ -1329,7 +1333,7 @@ void TrainSidebar::Start() // when start button is pressed
#if !defined GC_VIDEO_NONE
// enable media tree so we can change movie - mid workout
mediaTree->setEnabled(true);
#ifdef GC_HAVE_VLC // RLV currently only support for VLC
#ifdef USE_RLV
videosyncTree->setEnabled(true);
#endif
#endif
@@ -1367,7 +1371,7 @@ void TrainSidebar::Start() // when start button is pressed
// media or workouts whilst a workout is in progress
#if !defined GC_VIDEO_NONE
mediaTree->setEnabled(false);
#ifdef GC_HAVE_VLC // RLV currently only support for VLC
#ifdef USE_RLV
videosyncTree->setEnabled(false);
#endif
#endif
@@ -1490,7 +1494,7 @@ void TrainSidebar::Pause() // pause capture to recalibrate
#if !defined GC_VIDEO_NONE
mediaTree->setEnabled(false);
#ifdef GC_HAVE_VLC // RLV currently only support for VLC
#ifdef USE_RLV
videosyncTree->setEnabled(false);
#endif
#endif
@@ -1511,7 +1515,7 @@ void TrainSidebar::Pause() // pause capture to recalibrate
// enable media tree so we can change movie
#if !defined GC_VIDEO_NONE
mediaTree->setEnabled(true);
#ifdef GC_HAVE_VLC // RLV currently only support for VLC
#ifdef USE_RLV
videosyncTree->setEnabled(true);
#endif
#endif
@@ -1536,7 +1540,7 @@ void TrainSidebar::Stop(int deviceStatus) // when stop button is pressed
// media or workouts whilst a workout is in progress
#if !defined GC_VIDEO_NONE
mediaTree->setEnabled(true);
#ifdef GC_HAVE_VLC // RLV currently only support for VLC
#ifdef USE_RLV
videosyncTree->setEnabled(true);
#endif
#endif

View File

@@ -28,6 +28,10 @@
#include "VideoLayoutParser.h"
#include "HelpWhatsThis.h"
#if defined(GC_VIDEO_QT5)||defined(GC_VIDEO_QT6)
#include <QMediaMetaData>
#endif
class Lock
{
QRecursiveMutex& mutex;
@@ -37,7 +41,7 @@ public:
};
VideoWindow::VideoWindow(Context *context) :
GcChartWindow(context), context(context), m_MediaChanged(false), layoutSelector(NULL)
GcChartWindow(context), context(context), m_MediaChanged(false), layoutSelector(NULL), container(nullptr)
{
HelpWhatsThis *helpContents = new HelpWhatsThis(this);
this->setWhatsThis(helpContents->getWhatsThisText(HelpWhatsThis::ChartTrain_VideoPlayer));
@@ -101,9 +105,30 @@ VideoWindow::VideoWindow(Context *context) :
libvlc_media_player_set_xwindow (mp, container->winId());
#endif
#if defined(WIN32) || defined(Q_OS_LINUX)
} else {
// something went wrong !
init = false;
}
#endif
// Read the video layouts just to list the names for the layout selector
#if defined(GC_VIDEO_QT5)||defined(GC_VIDEO_QT6)
// USE QT VIDEO PLAYER
wd = new QVideoWidget(this);
wd->show();
mp = new QMediaPlayer(this);
mp->setVideoOutput(wd);
#if defined(GC_VIDEO_QT6)
mp->setAudioOutput(new QAudioOutput);
#endif
container = wd;
layout->addWidget(container);
#endif
#if defined(WIN32) || defined(Q_OS_LINUX)
if (init) {
// Read the video layouts just to list the names for the layout selector
readVideoLayout(-1);
// Create the layout selector form
@@ -134,25 +159,9 @@ VideoWindow::VideoWindow(Context *context) :
// Instantiate a layout as initial default
layoutChanged();
#endif
} else {
// something went wrong !
init = false;
}
#endif
#if defined(GC_VIDEO_QT5)||defined(GC_VIDEO_QT6)
// USE QT VIDEO PLAYER
wd = new QVideoWidget(this);
wd->show();
mp = new QMediaPlayer(this);
mp->setVideoOutput(wd);
layout->addWidget(wd);
#endif
setControls(c);
if (init) {
@@ -196,6 +205,8 @@ VideoWindow::~VideoWindow()
vlcDispatch.AsyncCall([capture_inst]() {libvlc_release(capture_inst); });
vlcDispatch.Drain();
delete container;
#endif
#if defined(GC_VIDEO_QT5)||defined(GC_VIDEO_QT6)
@@ -346,8 +357,15 @@ void VideoWindow::startPlayback()
m_MediaChanged = false;
#endif
#if defined(GC_VIDEO_QT5)||defined(GC_VIDEO_QT6)
#ifdef GC_VIDEO_QT5
mp->play();
#endif
#ifdef GC_VIDEO_QT6
// open the media object
float rate = 1.0f;
if (context->currentVideoSyncFile() && context->currentVideoSyncFile()->Points.count() > 1)
rate = 0.1f;
mp->setPlaybackRate(rate);
mp->play();
#endif
@@ -403,12 +421,28 @@ void VideoWindow::startPlayback()
}
#endif
#if defined(GC_VIDEO_QT5)||defined(GC_VIDEO_QT6)
// QT doesn't expose media frame rate so make due with duration.
double videoSyncDuration = currentVideoSyncFile->duration();
if (videoSyncDuration > 0) {
double mediaDuration = (double)mp->duration();
if (mediaDuration > 0) {
videoSyncTimeAdjustFactor = mediaDuration / videoSyncDuration;
double videoSyncFrameRate = currentVideoSyncFile->videoFrameRate();
if (videoSyncFrameRate > 0.) {
bool ok=false;
#ifdef GC_VIDEO_QT6
auto md = mp->metaData();
auto rate = md.value(QMediaMetaData::VideoFrameRate);
double mediaFrameRate = rate.toReal(&ok);
if (mediaFrameRate > 0.) {
videoSyncTimeAdjustFactor = videoSyncFrameRate / mediaFrameRate;
}
#endif
if (!ok) //fallback to duration
{
// QT5 doesn't expose media frame rate so make due with duration.
double videoSyncDuration = currentVideoSyncFile->duration();
if (videoSyncDuration > 0) {
double mediaDuration = (double)mp->duration();
if (mediaDuration > 0) {
videoSyncTimeAdjustFactor = mediaDuration / videoSyncDuration;
}
}
}
}
#endif
@@ -515,7 +549,7 @@ void VideoWindow::telemetryUpdate(RealtimeData rtd)
Lock lock(stateLock);
if (!hasActiveVideo())
return;
bool metric = GlobalContext::context()->useMetricUnits;
foreach(MeterWidget* p_meterWidget , m_metersWidget)
@@ -705,7 +739,7 @@ void VideoWindow::telemetryUpdate(RealtimeData rtd)
Q_UNUSED(rtd)
#endif
#ifdef GC_VIDEO_VLC
#if defined (GC_VIDEO_VLC) || defined (GC_VIDEO_QT6)
if (PlaybackState::Playing != state)
return;
@@ -773,8 +807,12 @@ void VideoWindow::telemetryUpdate(RealtimeData rtd)
float rate;
float video_time_shift_ms;
#ifdef GC_VIDEO_VLC
libvlc_media_player_t* capture_mp = this->mp;
video_time_shift_ms = (rfp.secs * 1000.0 - vlcDispatch.SyncCall<double>([capture_mp]{ return libvlc_media_player_get_time(capture_mp); }));
#else
video_time_shift_ms = (rfp.secs * 1000.0 - mp->position() );
#endif
if (rfp.kph == 0.0)
rate = 1.0;
else
@@ -784,25 +822,40 @@ void VideoWindow::telemetryUpdate(RealtimeData rtd)
if (fabs(video_time_shift_ms) > 5000)
{
double rfp_secs = rfp.secs;
#ifdef GC_VIDEO_VLC
vlcDispatch.AsyncCall([capture_mp, rfp_secs]{ libvlc_media_player_set_time(capture_mp, (libvlc_time_t)(rfp_secs * 1000.0)); });
#else
mp->setPosition(rfp_secs * 1000.0);
#endif
}
else {
// otherwise add "small" empiric corrective parameter to get video back to ghost position:
rate *= 1.0 + (video_time_shift_ms / 10000.0);
}
#ifdef GC_VIDEO_VLC
vlcDispatch.AsyncCall([capture_mp, rate]{ libvlc_media_player_set_pause(capture_mp, (rate < 0.01)); });
#else
if (rate < 0.01)
mp->pause();
else
mp->play();
#endif
// change video rate but only if there is a significant change
if ((rate != 0.0) && (fabs((rate - currentVideoRate) / rate) > 0.05))
{
#ifdef GC_VIDEO_VLC
vlcDispatch.AsyncCall([capture_mp, rate]{ libvlc_media_player_set_rate(capture_mp, rate); });
#else
mp->setPlaybackRate(rate);
#endif
currentVideoRate = rate;
}
}
#endif
#if defined(GC_VIDEO_QT5)||defined(GC_VIDEO_QT6)
#ifdef GC_VIDEO_QT5
//TODO
// // seek to ms position in current file
// mp->setPosition(ms);
@@ -821,7 +874,8 @@ void VideoWindow::seekPlayback(long ms)
#ifdef GC_VIDEO_VLC
if (!m) return;
#endif
// when we selected a videosync file in training mode (rlv...)
if (context->currentVideoSyncFile())
{
@@ -829,18 +883,18 @@ void VideoWindow::seekPlayback(long ms)
}
else
{
#ifdef GC_VIDEO_VLC
// seek to ms position in current file
libvlc_media_player_t* capture_mp = this->mp;
vlcDispatch.AsyncCall([capture_mp, ms]{ libvlc_media_player_set_time(capture_mp, (libvlc_time_t)ms); });
}
#endif
#else
#if defined(GC_VIDEO_QT5)||defined(GC_VIDEO_QT6)
Q_UNUSED(ms)
//TODO
// // seek to ms position in current file
// mp->setPosition(ms);
mp->setPosition(ms);
#else
Q_UNUSED(ms)
#endif
#endif
}
}
void VideoWindow::mediaSelected(QString filename)
@@ -898,7 +952,9 @@ void VideoWindow::mediaSelected(QString filename)
#endif
#ifdef GC_VIDEO_QT6
// QT MEDIA
mp->setSource(QUrl::fromLocalFile(filename));
if (filename != "")
mp->setSource(QUrl::fromLocalFile(filename));
#endif
if(context->isRunning) startPlayback();
}
@@ -923,7 +979,6 @@ MediaHelper::MediaHelper()
supported << ".MXF";
supported << ".VOB";
supported << ".WMV";
}
MediaHelper::~MediaHelper()

View File

@@ -107,7 +107,9 @@ extern "C" {
#include <QVideoWidget>
#include <QMediaPlayer>
#endif
#ifdef GC_VIDEO_QT6
#include <QAudioOutput>
#endif
#ifdef GC_VIDEO_QT5
#include <QMediaContent>
#endif