mirror of
https://github.com/obsproject/obs-studio.git
synced 2026-01-24 22:28:34 -05:00
When a source file contains an explicit include with a filename following the "moc_<actual-filename>.cpp" pattern, then CMake's AUTOMOC generation tool will recognize the matching pair and generate the replacement header file and add the required include directory entries. For all files which do contain Q_OBJECT or similar declarations but do not have an explicit include directive, the global mocs_compilation.cpp file will still be generated (which groups all "missing" generated headers). The larger this global file is, the more expensive incremental compilation will be as this file (and all its contained generated headers) will be re-generated regardless of whether actual changes occurred.
554 lines
13 KiB
C++
554 lines
13 KiB
C++
#include "window-basic-main.hpp"
|
|
#include "moc_media-controls.cpp"
|
|
#include "obs-app.hpp"
|
|
#include <QToolTip>
|
|
#include <QStyle>
|
|
#include <QMenu>
|
|
|
|
#include "ui_media-controls.h"
|
|
|
|
void MediaControls::OBSMediaStopped(void *data, calldata_t *)
|
|
{
|
|
MediaControls *media = static_cast<MediaControls *>(data);
|
|
QMetaObject::invokeMethod(media, "SetRestartState");
|
|
}
|
|
|
|
void MediaControls::OBSMediaPlay(void *data, calldata_t *)
|
|
{
|
|
MediaControls *media = static_cast<MediaControls *>(data);
|
|
QMetaObject::invokeMethod(media, "SetPlayingState");
|
|
}
|
|
|
|
void MediaControls::OBSMediaPause(void *data, calldata_t *)
|
|
{
|
|
MediaControls *media = static_cast<MediaControls *>(data);
|
|
QMetaObject::invokeMethod(media, "SetPausedState");
|
|
}
|
|
|
|
void MediaControls::OBSMediaStarted(void *data, calldata_t *)
|
|
{
|
|
MediaControls *media = static_cast<MediaControls *>(data);
|
|
QMetaObject::invokeMethod(media, "SetPlayingState");
|
|
}
|
|
|
|
void MediaControls::OBSMediaNext(void *data, calldata_t *)
|
|
{
|
|
MediaControls *media = static_cast<MediaControls *>(data);
|
|
QMetaObject::invokeMethod(media, "UpdateSlideCounter");
|
|
}
|
|
|
|
void MediaControls::OBSMediaPrevious(void *data, calldata_t *)
|
|
{
|
|
MediaControls *media = static_cast<MediaControls *>(data);
|
|
QMetaObject::invokeMethod(media, "UpdateSlideCounter");
|
|
}
|
|
|
|
MediaControls::MediaControls(QWidget *parent)
|
|
: QWidget(parent),
|
|
ui(new Ui::MediaControls)
|
|
{
|
|
ui->setupUi(this);
|
|
ui->playPauseButton->setProperty("themeID", "playIcon");
|
|
ui->previousButton->setProperty("themeID", "previousIcon");
|
|
ui->nextButton->setProperty("themeID", "nextIcon");
|
|
ui->stopButton->setProperty("themeID", "stopIcon");
|
|
setFocusPolicy(Qt::StrongFocus);
|
|
|
|
connect(&mediaTimer, &QTimer::timeout, this,
|
|
&MediaControls::SetSliderPosition);
|
|
connect(&seekTimer, &QTimer::timeout, this,
|
|
&MediaControls::SeekTimerCallback);
|
|
connect(ui->slider, &AbsoluteSlider::sliderPressed, this,
|
|
&MediaControls::AbsoluteSliderClicked);
|
|
connect(ui->slider, &AbsoluteSlider::absoluteSliderHovered, this,
|
|
&MediaControls::AbsoluteSliderHovered);
|
|
connect(ui->slider, &AbsoluteSlider::sliderReleased, this,
|
|
&MediaControls::AbsoluteSliderReleased);
|
|
connect(ui->slider, &AbsoluteSlider::sliderMoved, this,
|
|
&MediaControls::AbsoluteSliderMoved);
|
|
|
|
countDownTimer = config_get_bool(App()->GlobalConfig(), "BasicWindow",
|
|
"MediaControlsCountdownTimer");
|
|
|
|
QAction *restartAction = new QAction(this);
|
|
restartAction->setShortcutContext(Qt::WidgetWithChildrenShortcut);
|
|
restartAction->setShortcut({Qt::Key_R});
|
|
connect(restartAction, &QAction::triggered, this,
|
|
&MediaControls::RestartMedia);
|
|
addAction(restartAction);
|
|
|
|
QAction *sliderFoward = new QAction(this);
|
|
sliderFoward->setShortcutContext(Qt::WidgetWithChildrenShortcut);
|
|
connect(sliderFoward, &QAction::triggered, this,
|
|
&MediaControls::MoveSliderFoward);
|
|
sliderFoward->setShortcut({Qt::Key_Right});
|
|
addAction(sliderFoward);
|
|
|
|
QAction *sliderBack = new QAction(this);
|
|
sliderBack->setShortcutContext(Qt::WidgetWithChildrenShortcut);
|
|
connect(sliderBack, &QAction::triggered, this,
|
|
&MediaControls::MoveSliderBackwards);
|
|
sliderBack->setShortcut({Qt::Key_Left});
|
|
addAction(sliderBack);
|
|
|
|
QAction *playPause = new QAction(this);
|
|
playPause->setShortcutContext(Qt::WidgetWithChildrenShortcut);
|
|
connect(playPause, &QAction::triggered, this,
|
|
&MediaControls::on_playPauseButton_clicked);
|
|
playPause->setShortcut({Qt::Key_Space});
|
|
addAction(playPause);
|
|
}
|
|
|
|
MediaControls::~MediaControls() {}
|
|
|
|
bool MediaControls::MediaPaused()
|
|
{
|
|
OBSSource source = OBSGetStrongRef(weakSource);
|
|
if (!source) {
|
|
return false;
|
|
}
|
|
|
|
obs_media_state state = obs_source_media_get_state(source);
|
|
return state == OBS_MEDIA_STATE_PAUSED;
|
|
}
|
|
|
|
int64_t MediaControls::GetSliderTime(int val)
|
|
{
|
|
OBSSource source = OBSGetStrongRef(weakSource);
|
|
if (!source) {
|
|
return 0;
|
|
}
|
|
|
|
float percent = (float)val / (float)ui->slider->maximum();
|
|
float duration = (float)obs_source_media_get_duration(source);
|
|
int64_t seekTo = (int64_t)(percent * duration);
|
|
|
|
return seekTo;
|
|
}
|
|
|
|
void MediaControls::AbsoluteSliderClicked()
|
|
{
|
|
OBSSource source = OBSGetStrongRef(weakSource);
|
|
if (!source) {
|
|
return;
|
|
}
|
|
|
|
obs_media_state state = obs_source_media_get_state(source);
|
|
|
|
if (state == OBS_MEDIA_STATE_PAUSED) {
|
|
prevPaused = true;
|
|
} else if (state == OBS_MEDIA_STATE_PLAYING) {
|
|
prevPaused = false;
|
|
PauseMedia();
|
|
StopMediaTimer();
|
|
}
|
|
|
|
seek = ui->slider->value();
|
|
seekTimer.start(100);
|
|
}
|
|
|
|
void MediaControls::AbsoluteSliderReleased()
|
|
{
|
|
OBSSource source = OBSGetStrongRef(weakSource);
|
|
if (!source) {
|
|
return;
|
|
}
|
|
|
|
if (seekTimer.isActive()) {
|
|
seekTimer.stop();
|
|
if (lastSeek != seek) {
|
|
obs_source_media_set_time(source, GetSliderTime(seek));
|
|
}
|
|
|
|
UpdateLabels(seek);
|
|
seek = lastSeek = -1;
|
|
}
|
|
|
|
if (!prevPaused) {
|
|
PlayMedia();
|
|
StartMediaTimer();
|
|
}
|
|
}
|
|
|
|
void MediaControls::AbsoluteSliderHovered(int val)
|
|
{
|
|
float seconds = ((float)GetSliderTime(val) / 1000.0f);
|
|
QToolTip::showText(QCursor::pos(), FormatSeconds((int)seconds), this);
|
|
}
|
|
|
|
void MediaControls::AbsoluteSliderMoved(int val)
|
|
{
|
|
if (seekTimer.isActive()) {
|
|
seek = val;
|
|
UpdateLabels(seek);
|
|
}
|
|
}
|
|
|
|
void MediaControls::SeekTimerCallback()
|
|
{
|
|
if (lastSeek != seek) {
|
|
OBSSource source = OBSGetStrongRef(weakSource);
|
|
if (source) {
|
|
obs_source_media_set_time(source, GetSliderTime(seek));
|
|
}
|
|
lastSeek = seek;
|
|
}
|
|
}
|
|
|
|
void MediaControls::StartMediaTimer()
|
|
{
|
|
if (isSlideshow)
|
|
return;
|
|
|
|
if (!mediaTimer.isActive())
|
|
mediaTimer.start(1000);
|
|
}
|
|
|
|
void MediaControls::StopMediaTimer()
|
|
{
|
|
if (mediaTimer.isActive())
|
|
mediaTimer.stop();
|
|
}
|
|
|
|
void MediaControls::SetPlayingState()
|
|
{
|
|
ui->slider->setEnabled(true);
|
|
ui->playPauseButton->setProperty("themeID", "pauseIcon");
|
|
ui->playPauseButton->style()->unpolish(ui->playPauseButton);
|
|
ui->playPauseButton->style()->polish(ui->playPauseButton);
|
|
ui->playPauseButton->setToolTip(
|
|
QTStr("ContextBar.MediaControls.PauseMedia"));
|
|
|
|
prevPaused = false;
|
|
|
|
UpdateSlideCounter();
|
|
StartMediaTimer();
|
|
}
|
|
|
|
void MediaControls::SetPausedState()
|
|
{
|
|
ui->playPauseButton->setProperty("themeID", "playIcon");
|
|
ui->playPauseButton->style()->unpolish(ui->playPauseButton);
|
|
ui->playPauseButton->style()->polish(ui->playPauseButton);
|
|
ui->playPauseButton->setToolTip(
|
|
QTStr("ContextBar.MediaControls.PlayMedia"));
|
|
|
|
StopMediaTimer();
|
|
}
|
|
|
|
void MediaControls::SetRestartState()
|
|
{
|
|
ui->playPauseButton->setProperty("themeID", "restartIcon");
|
|
ui->playPauseButton->style()->unpolish(ui->playPauseButton);
|
|
ui->playPauseButton->style()->polish(ui->playPauseButton);
|
|
ui->playPauseButton->setToolTip(
|
|
QTStr("ContextBar.MediaControls.RestartMedia"));
|
|
|
|
ui->slider->setValue(0);
|
|
|
|
if (!isSlideshow) {
|
|
ui->timerLabel->setText("--:--:--");
|
|
ui->durationLabel->setText("--:--:--");
|
|
} else {
|
|
ui->timerLabel->setText("-");
|
|
ui->durationLabel->setText("-");
|
|
}
|
|
|
|
ui->slider->setEnabled(false);
|
|
|
|
StopMediaTimer();
|
|
}
|
|
|
|
void MediaControls::RefreshControls()
|
|
{
|
|
OBSSource source;
|
|
source = OBSGetStrongRef(weakSource);
|
|
|
|
uint32_t flags = 0;
|
|
const char *id = nullptr;
|
|
|
|
if (source) {
|
|
flags = obs_source_get_output_flags(source);
|
|
id = obs_source_get_unversioned_id(source);
|
|
}
|
|
|
|
if (!source || !(flags & OBS_SOURCE_CONTROLLABLE_MEDIA)) {
|
|
SetRestartState();
|
|
setEnabled(false);
|
|
hide();
|
|
return;
|
|
} else {
|
|
setEnabled(true);
|
|
show();
|
|
}
|
|
|
|
bool has_playlist = strcmp(id, "ffmpeg_source") != 0;
|
|
ui->previousButton->setVisible(has_playlist);
|
|
ui->nextButton->setVisible(has_playlist);
|
|
|
|
isSlideshow = strcmp(id, "slideshow") == 0;
|
|
ui->slider->setVisible(!isSlideshow);
|
|
ui->emptySpaceAgain->setVisible(isSlideshow);
|
|
|
|
obs_media_state state = obs_source_media_get_state(source);
|
|
|
|
switch (state) {
|
|
case OBS_MEDIA_STATE_STOPPED:
|
|
case OBS_MEDIA_STATE_ENDED:
|
|
case OBS_MEDIA_STATE_NONE:
|
|
SetRestartState();
|
|
break;
|
|
case OBS_MEDIA_STATE_PLAYING:
|
|
SetPlayingState();
|
|
break;
|
|
case OBS_MEDIA_STATE_PAUSED:
|
|
SetPausedState();
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (isSlideshow)
|
|
UpdateSlideCounter();
|
|
else
|
|
SetSliderPosition();
|
|
}
|
|
|
|
OBSSource MediaControls::GetSource()
|
|
{
|
|
return OBSGetStrongRef(weakSource);
|
|
}
|
|
|
|
void MediaControls::SetSource(OBSSource source)
|
|
{
|
|
sigs.clear();
|
|
|
|
if (source) {
|
|
weakSource = OBSGetWeakRef(source);
|
|
signal_handler_t *sh = obs_source_get_signal_handler(source);
|
|
sigs.emplace_back(sh, "media_play", OBSMediaPlay, this);
|
|
sigs.emplace_back(sh, "media_pause", OBSMediaPause, this);
|
|
sigs.emplace_back(sh, "media_restart", OBSMediaPlay, this);
|
|
sigs.emplace_back(sh, "media_stopped", OBSMediaStopped, this);
|
|
sigs.emplace_back(sh, "media_started", OBSMediaStarted, this);
|
|
sigs.emplace_back(sh, "media_ended", OBSMediaStopped, this);
|
|
sigs.emplace_back(sh, "media_next", OBSMediaNext, this);
|
|
sigs.emplace_back(sh, "media_previous", OBSMediaPrevious, this);
|
|
} else {
|
|
weakSource = nullptr;
|
|
}
|
|
|
|
RefreshControls();
|
|
}
|
|
|
|
void MediaControls::SetSliderPosition()
|
|
{
|
|
OBSSource source = OBSGetStrongRef(weakSource);
|
|
if (!source) {
|
|
return;
|
|
}
|
|
|
|
float time = (float)obs_source_media_get_time(source);
|
|
float duration = (float)obs_source_media_get_duration(source);
|
|
|
|
float sliderPosition;
|
|
|
|
if (duration)
|
|
sliderPosition =
|
|
(time / duration) * (float)ui->slider->maximum();
|
|
else
|
|
sliderPosition = 0.0f;
|
|
|
|
ui->slider->setValue((int)sliderPosition);
|
|
UpdateLabels((int)sliderPosition);
|
|
}
|
|
|
|
QString MediaControls::FormatSeconds(int totalSeconds)
|
|
{
|
|
int seconds = totalSeconds % 60;
|
|
int totalMinutes = totalSeconds / 60;
|
|
int minutes = totalMinutes % 60;
|
|
int hours = totalMinutes / 60;
|
|
|
|
return QString::asprintf("%02d:%02d:%02d", hours, minutes, seconds);
|
|
}
|
|
|
|
void MediaControls::on_playPauseButton_clicked()
|
|
{
|
|
OBSSource source = OBSGetStrongRef(weakSource);
|
|
if (!source) {
|
|
return;
|
|
}
|
|
|
|
obs_media_state state = obs_source_media_get_state(source);
|
|
|
|
switch (state) {
|
|
case OBS_MEDIA_STATE_STOPPED:
|
|
case OBS_MEDIA_STATE_ENDED:
|
|
RestartMedia();
|
|
break;
|
|
case OBS_MEDIA_STATE_PLAYING:
|
|
PauseMedia();
|
|
break;
|
|
case OBS_MEDIA_STATE_PAUSED:
|
|
PlayMedia();
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
void MediaControls::RestartMedia()
|
|
{
|
|
OBSSource source = OBSGetStrongRef(weakSource);
|
|
if (source) {
|
|
obs_source_media_restart(source);
|
|
}
|
|
}
|
|
|
|
void MediaControls::PlayMedia()
|
|
{
|
|
OBSSource source = OBSGetStrongRef(weakSource);
|
|
if (source) {
|
|
obs_source_media_play_pause(source, false);
|
|
}
|
|
}
|
|
|
|
void MediaControls::PauseMedia()
|
|
{
|
|
OBSSource source = OBSGetStrongRef(weakSource);
|
|
if (source) {
|
|
obs_source_media_play_pause(source, true);
|
|
}
|
|
}
|
|
|
|
void MediaControls::StopMedia()
|
|
{
|
|
OBSSource source = OBSGetStrongRef(weakSource);
|
|
if (source) {
|
|
obs_source_media_stop(source);
|
|
}
|
|
}
|
|
|
|
void MediaControls::PlaylistNext()
|
|
{
|
|
OBSSource source = OBSGetStrongRef(weakSource);
|
|
if (source) {
|
|
obs_source_media_next(source);
|
|
}
|
|
}
|
|
|
|
void MediaControls::PlaylistPrevious()
|
|
{
|
|
OBSSource source = OBSGetStrongRef(weakSource);
|
|
if (source) {
|
|
obs_source_media_previous(source);
|
|
}
|
|
}
|
|
|
|
void MediaControls::on_stopButton_clicked()
|
|
{
|
|
StopMedia();
|
|
}
|
|
|
|
void MediaControls::on_nextButton_clicked()
|
|
{
|
|
PlaylistNext();
|
|
}
|
|
|
|
void MediaControls::on_previousButton_clicked()
|
|
{
|
|
PlaylistPrevious();
|
|
}
|
|
|
|
void MediaControls::on_durationLabel_clicked()
|
|
{
|
|
countDownTimer = !countDownTimer;
|
|
|
|
config_set_bool(App()->GlobalConfig(), "BasicWindow",
|
|
"MediaControlsCountdownTimer", countDownTimer);
|
|
|
|
if (MediaPaused())
|
|
SetSliderPosition();
|
|
}
|
|
|
|
void MediaControls::MoveSliderFoward(int seconds)
|
|
{
|
|
OBSSource source = OBSGetStrongRef(weakSource);
|
|
|
|
if (!source)
|
|
return;
|
|
|
|
int ms = obs_source_media_get_time(source);
|
|
ms += seconds * 1000;
|
|
|
|
obs_source_media_set_time(source, ms);
|
|
SetSliderPosition();
|
|
}
|
|
|
|
void MediaControls::MoveSliderBackwards(int seconds)
|
|
{
|
|
OBSSource source = OBSGetStrongRef(weakSource);
|
|
|
|
if (!source)
|
|
return;
|
|
|
|
int ms = obs_source_media_get_time(source);
|
|
ms -= seconds * 1000;
|
|
|
|
obs_source_media_set_time(source, ms);
|
|
SetSliderPosition();
|
|
}
|
|
|
|
void MediaControls::UpdateSlideCounter()
|
|
{
|
|
if (!isSlideshow)
|
|
return;
|
|
|
|
OBSSource source = OBSGetStrongRef(weakSource);
|
|
|
|
if (!source)
|
|
return;
|
|
|
|
proc_handler_t *ph = obs_source_get_proc_handler(source);
|
|
calldata_t cd = {};
|
|
|
|
proc_handler_call(ph, "current_index", &cd);
|
|
int slide = calldata_int(&cd, "current_index");
|
|
|
|
proc_handler_call(ph, "total_files", &cd);
|
|
int total = calldata_int(&cd, "total_files");
|
|
calldata_free(&cd);
|
|
|
|
if (total > 0) {
|
|
ui->timerLabel->setText(QString::number(slide + 1));
|
|
ui->durationLabel->setText(QString::number(total));
|
|
} else {
|
|
ui->timerLabel->setText("-");
|
|
ui->durationLabel->setText("-");
|
|
}
|
|
}
|
|
|
|
void MediaControls::UpdateLabels(int val)
|
|
{
|
|
OBSSource source = OBSGetStrongRef(weakSource);
|
|
if (!source) {
|
|
return;
|
|
}
|
|
|
|
float duration = (float)obs_source_media_get_duration(source);
|
|
float percent = (float)val / (float)ui->slider->maximum();
|
|
|
|
float time = percent * duration;
|
|
|
|
ui->timerLabel->setText(FormatSeconds((int)(time / 1000.0f)));
|
|
|
|
if (!countDownTimer)
|
|
ui->durationLabel->setText(
|
|
FormatSeconds((int)(duration / 1000.0f)));
|
|
else
|
|
ui->durationLabel->setText(
|
|
QString("-") +
|
|
FormatSeconds((int)((duration - time) / 1000.0f)));
|
|
}
|