/* -*- 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/qt/QtUtils.hxx>
#include <vcl/scheduler.hxx>
#include "QtFrameGrabber.hxx"
#include <QtFrameGrabber.moc>
using namespace ::com::sun::star;
namespace
{
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);
BitmapEx aBitmapEx;
if (aReader.read(aBitmapEx))
return Graphic(aBitmapEx).GetXGraphic();
return nullptr;
}
}
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& rE
rrorString)
{
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: */