1
0
Fork 0
libreoffice/avmedia/source/qt6/QtPlayer.cxx
Daniel Baumann 8e63e14cf6
Adding upstream version 4:25.2.3.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
2025-06-22 16:20:04 +02:00

334 lines
8.9 KiB
C++

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#include <sal/config.h>
#include <QtCore/QCoreApplication>
#include <QtCore/QUrl>
#include <QtMultimedia/QAudioOutput>
#include <QtMultimedia/QMediaMetaData>
#include <QtMultimediaWidgets/QVideoWidget>
#include <QtWidgets/QLabel>
#include <QtWidgets/QLayout>
#include <cppuhelper/supportsservice.hxx>
#include <sal/log.hxx>
#include <rtl/string.hxx>
#include <tools/link.hxx>
#include <vcl/BitmapTools.hxx>
#include <vcl/graph.hxx>
#include <vcl/qt/QtUtils.hxx>
#include <vcl/svapp.hxx>
#include <vcl/syschild.hxx>
#include <vcl/sysdata.hxx>
#include <vcl/timer.hxx>
#include <gstwindow.hxx>
#include "QtFrameGrabber.hxx"
#include "QtPlayer.hxx"
#include <QtPlayer.moc>
using namespace ::com::sun::star;
namespace avmedia::qt
{
QtPlayer::QtPlayer()
: QtPlayer_BASE(m_aMutex)
, m_pMediaWidgetParent(nullptr)
{
}
bool QtPlayer::create(const OUString& rURL)
{
const QUrl aQUrl(toQString(rURL));
if (!aQUrl.isValid() || !aQUrl.isLocalFile())
return false;
m_xMediaPlayer = std::make_unique<QMediaPlayer>();
m_xMediaPlayer->setSource(aQUrl);
QAudioOutput* pAudioOutput = new QAudioOutput;
pAudioOutput->setVolume(50);
m_xMediaPlayer->setAudioOutput(pAudioOutput);
return true;
}
void SAL_CALL QtPlayer::start()
{
osl::MutexGuard aGuard(m_aMutex);
assert(m_xMediaPlayer);
m_xMediaPlayer->play();
}
void SAL_CALL QtPlayer::stop()
{
osl::MutexGuard aGuard(m_aMutex);
if (m_xMediaPlayer)
{
// don't use QMediaPlayer::stop because XPlayer::stop should leave the position unchanged
m_xMediaPlayer->pause();
}
}
sal_Bool SAL_CALL QtPlayer::isPlaying()
{
osl::MutexGuard aGuard(m_aMutex);
#if QT_VERSION >= QT_VERSION_CHECK(6, 5, 0)
assert(m_xMediaPlayer);
return m_xMediaPlayer->isPlaying();
#else
return false;
#endif
}
double SAL_CALL QtPlayer::getDuration()
{
osl::MutexGuard aGuard(m_aMutex);
assert(m_xMediaPlayer);
return m_xMediaPlayer->duration() / 1000.0;
}
void SAL_CALL QtPlayer::setMediaTime(double fTime)
{
osl::MutexGuard aGuard(m_aMutex);
assert(m_xMediaPlayer);
m_xMediaPlayer->setPosition(fTime * 1000);
}
double SAL_CALL QtPlayer::getMediaTime()
{
osl::MutexGuard aGuard(m_aMutex);
assert(m_xMediaPlayer);
return m_xMediaPlayer->position() / 1000.0;
}
void SAL_CALL QtPlayer::setPlaybackLoop(sal_Bool bSet)
{
assert(m_xMediaPlayer);
const int nLoops = bSet ? QMediaPlayer::Infinite : QMediaPlayer::Once;
m_xMediaPlayer->setLoops(nLoops);
}
sal_Bool SAL_CALL QtPlayer::isPlaybackLoop()
{
assert(m_xMediaPlayer);
return m_xMediaPlayer->loops() == QMediaPlayer::Infinite;
}
void SAL_CALL QtPlayer::setVolumeDB(sal_Int16 nVolumeDB)
{
osl::MutexGuard aGuard(m_aMutex);
// range is -40 for silence to 0 for full volume
const sal_Int16 nVolume = std::clamp<sal_Int16>(nVolumeDB, -40, 0);
double fValue = (nVolume + 40) / 40.0;
assert(m_xMediaPlayer);
QAudioOutput* pAudioOutput = m_xMediaPlayer->audioOutput();
assert(pAudioOutput);
pAudioOutput->setVolume(fValue);
}
sal_Int16 SAL_CALL QtPlayer::getVolumeDB()
{
osl::MutexGuard aGuard(m_aMutex);
assert(m_xMediaPlayer);
QAudioOutput* pAudioOutput = m_xMediaPlayer->audioOutput();
assert(pAudioOutput);
double fVolume = pAudioOutput->volume();
return (fVolume * 40) - 40;
}
void SAL_CALL QtPlayer::setMute(sal_Bool bSet)
{
osl::MutexGuard aGuard(m_aMutex);
assert(m_xMediaPlayer);
QAudioOutput* pAudioOutput = m_xMediaPlayer->audioOutput();
assert(pAudioOutput);
pAudioOutput->setMuted(bSet);
}
sal_Bool SAL_CALL QtPlayer::isMute()
{
osl::MutexGuard aGuard(m_aMutex);
assert(m_xMediaPlayer);
QAudioOutput* pAudioOutput = m_xMediaPlayer->audioOutput();
assert(pAudioOutput);
return pAudioOutput->isMuted();
}
awt::Size SAL_CALL QtPlayer::getPreferredPlayerWindowSize()
{
osl::MutexGuard aGuard(m_aMutex);
assert(m_xMediaPlayer);
// if media hasn't been loaded yet, ensure this happens, since
// retrieving resolution doesn't work reliably otherwise
if (m_xMediaPlayer->mediaStatus() == QMediaPlayer::LoadingMedia)
{
m_xMediaPlayer->play();
while (m_xMediaPlayer->mediaStatus() == QMediaPlayer::LoadingMedia)
QCoreApplication::processEvents();
m_xMediaPlayer->stop();
}
const QMediaMetaData aMetaData = m_xMediaPlayer->metaData();
const QVariant aResolutionVariant = aMetaData.value(QMediaMetaData::Resolution);
if (aResolutionVariant.canConvert<QSize>())
{
const QSize aResolution = aResolutionVariant.value<QSize>();
return awt::Size(aResolution.width(), aResolution.height());
}
return awt::Size(0, 0);
}
uno::Reference<::media::XPlayerWindow>
SAL_CALL QtPlayer::createPlayerWindow(const uno::Sequence<uno::Any>& rArguments)
{
osl::MutexGuard aGuard(m_aMutex);
if (rArguments.getLength() > 1)
rArguments[1] >>= m_aPlayerWidgetRect;
if (rArguments.getLength() <= 2)
{
uno::Reference<::media::XPlayerWindow> xRet = new ::avmedia::gstreamer::Window;
return xRet;
}
sal_IntPtr pIntPtr = 0;
rArguments[2] >>= pIntPtr;
SystemChildWindow* pParentWindow = reinterpret_cast<SystemChildWindow*>(pIntPtr);
if (!pParentWindow)
return nullptr;
const SystemEnvData* pParentEnvData = pParentWindow->GetSystemData();
if (!pParentEnvData)
return nullptr;
m_pMediaWidgetParent = static_cast<QWidget*>(pParentEnvData->pWidget);
assert(m_pMediaWidgetParent);
// while media is loading, QMediaPlayer::hasVideo doesn't yet return
// whether media actually has video; defer creating audio/video widget
if (m_xMediaPlayer->mediaStatus() == QMediaPlayer::LoadingMedia)
{
connect(m_xMediaPlayer.get(), &QMediaPlayer::mediaStatusChanged, this,
&QtPlayer::createMediaPlayerWidget, Qt::SingleShotConnection);
}
else
{
createMediaPlayerWidget();
}
uno::Reference<::media::XPlayerWindow> xRet = new ::avmedia::gstreamer::Window;
return xRet;
}
uno::Reference<media::XFrameGrabber> SAL_CALL QtPlayer::createFrameGrabber()
{
osl::MutexGuard aGuard(m_aMutex);
rtl::Reference<QtFrameGrabber> xFrameGrabber = new QtFrameGrabber(m_xMediaPlayer->source());
return xFrameGrabber;
}
OUString SAL_CALL QtPlayer::getImplementationName()
{
return u"com.sun.star.comp.avmedia.Player_Qt"_ustr;
}
sal_Bool SAL_CALL QtPlayer::supportsService(const OUString& rServiceName)
{
return cppu::supportsService(this, rServiceName);
}
uno::Sequence<OUString> SAL_CALL QtPlayer::getSupportedServiceNames()
{
return { u"com.sun.star.media.Player_Qt"_ustr };
}
void SAL_CALL QtPlayer::disposing()
{
osl::MutexGuard aGuard(m_aMutex);
stop();
QtPlayer_BASE::disposing();
}
QtPlayer::~QtPlayer()
{
if (m_xMediaPlayer)
{
// ensure output objects get deleted as QMediaPlayer doesn't take ownership of them
std::unique_ptr<QObject> xVideoWidget(m_xMediaPlayer->videoOutput());
std::unique_ptr<QAudioOutput> xAudioOutput(m_xMediaPlayer->audioOutput());
}
m_xMediaPlayer.reset();
}
void QtPlayer::createMediaPlayerWidget()
{
assert(m_xMediaPlayer);
assert(m_xMediaPlayer->mediaStatus() != QMediaPlayer::LoadingMedia
&& "Media is still loading, detecting video availability not possible.");
assert(m_pMediaWidgetParent && "Parent for media widget not set");
// if media contains video, show the video output,
// otherwise show an audio icon as a placeholder
QWidget* pWidget;
if (m_xMediaPlayer->hasVideo())
{
QVideoWidget* pVideoWidget = new QVideoWidget(m_pMediaWidgetParent);
pVideoWidget->setAspectRatioMode(Qt::IgnoreAspectRatio);
assert(!m_xMediaPlayer->videoOutput() && "Video output already set.");
m_xMediaPlayer->setVideoOutput(pVideoWidget);
pWidget = pVideoWidget;
}
else
{
QPixmap aAudioPixmap = loadQPixmapIcon(u"avmedia/res/avaudiologo.png"_ustr);
aAudioPixmap
= aAudioPixmap.scaled(QSize(m_aPlayerWidgetRect.Width, m_aPlayerWidgetRect.Height));
QLabel* pLabel = new QLabel;
pLabel->setPixmap(aAudioPixmap);
pWidget = pLabel;
}
assert(pWidget);
pWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
// retrieve the layout (which is set in the QtObjectWidget ctor)
QLayout* pLayout = m_pMediaWidgetParent->layout();
assert(pLayout);
assert(pLayout->count() == 0 && "Layout already has a widget set");
pLayout->addWidget(pWidget);
}
} // namespace
/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */