115 lines
3.3 KiB
C++
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: */
|