1
0
Fork 0
libreoffice/avmedia/source/qt6/QtFrameGrabber.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

115 lines
3.3 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 <QtCore/QBuffer>
#include <QtCore/QByteArray>
#include <sal/log.hxx>
#include <vcl/filter/PngImageReader.hxx>
#include <vcl/graph.hxx>
#include <vcl/image.hxx>
#include <vcl/scheduler.hxx>
#include "QtFrameGrabber.hxx"
#include <QtFrameGrabber.moc>
using namespace ::com::sun::star;
namespace
{
inline OUString toOUString(const QString& s)
{
return OUString(reinterpret_cast<const sal_Unicode*>(s.data()), s.length());
}
uno::Reference<css::graphic::XGraphic> toXGraphic(const QImage& rImage)
{
QByteArray aData;
QBuffer aBuffer(&aData);
rImage.save(&aBuffer, "PNG");
SvMemoryStream aStream(aData.data(), aData.size(), StreamMode::READ);
vcl::PngImageReader aReader(aStream);
Graphic aGraphic;
aReader.read(aGraphic);
return aGraphic.GetXGraphic();
}
}
namespace avmedia::qt
{
QtFrameGrabber::QtFrameGrabber(const QUrl& rSourceUrl)
: m_bWaitingForFrame(false)
{
m_xMediaPlayer = std::make_unique<QMediaPlayer>();
m_xMediaPlayer->setSource(rSourceUrl);
m_xVideoSink = std::make_unique<QVideoSink>();
m_xMediaPlayer->setVideoSink(m_xVideoSink.get());
connect(m_xMediaPlayer.get(), &QMediaPlayer::errorOccurred, this,
&QtFrameGrabber::onErrorOccured, Qt::SingleShotConnection);
}
void QtFrameGrabber::onErrorOccured(QMediaPlayer::Error eError, const QString& rErrorString)
{
std::lock_guard aLock(m_aMutex);
SAL_WARN("avmedia", "Media playback error occurred when trying to grab frame: "
<< toOUString(rErrorString) << ", code: " << eError);
m_bWaitingForFrame = false;
}
void QtFrameGrabber::onVideoFrameChanged(const QVideoFrame& rFrame)
{
std::lock_guard aLock(m_aMutex);
const QImage aImage = rFrame.toImage();
m_xGraphic = toXGraphic(aImage);
m_bWaitingForFrame = false;
}
css::uno::Reference<css::graphic::XGraphic> SAL_CALL QtFrameGrabber::grabFrame(double fMediaTime)
{
std::lock_guard aLock(m_aMutex);
m_xMediaPlayer->setPosition(fMediaTime * 1000);
// in order to get a video frame, connect to videoFrameChanged signal and start playing
// until the first frame has been received
m_bWaitingForFrame = true;
connect(m_xVideoSink.get(), &QVideoSink::videoFrameChanged, this,
&QtFrameGrabber::onVideoFrameChanged, Qt::SingleShotConnection);
m_xMediaPlayer->play();
while (m_bWaitingForFrame)
{
// QMediaPlayer::hasVideo() result isn't valid while media is loading
if (m_xMediaPlayer->mediaStatus() != QMediaPlayer::LoadingMedia
&& !m_xMediaPlayer->hasVideo())
{
// There's no video, don't wait for frame
m_bWaitingForFrame = false;
}
else
{
Scheduler::ProcessEventsToIdle();
}
}
m_xMediaPlayer->stop();
uno::Reference<css::graphic::XGraphic> xGraphic = m_xGraphic;
m_xGraphic.clear();
return xGraphic;
}
}; // namespace
/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */