mirror of https://code.videolan.org/videolan/vlc
qt: vlcaccess image provider
artwork may reference a network resource, so far we were using QNetwork to read these resources, but it has some drawbacks * The protocol for the artwork may not be handled by QNetwork * The access to the artwork may require credentials that will likely be the same as the one required to access the media * QNetwork may not be present as this is not a requirement for building VLC Image may require to be loaded using VLC access using special URI image://vlcaccess/?uri=......
This commit is contained in:
parent
f7498f6b19
commit
d8d598e860
|
@ -298,6 +298,7 @@ libqt_plugin_la_SOURCES = \
|
|||
util/base_model.hpp util/base_model_p.hpp util/base_model.cpp \
|
||||
util/color_scheme_model.cpp util/color_scheme_model.hpp \
|
||||
util/color_svg_image_provider.cpp util/color_svg_image_provider.hpp \
|
||||
util/vlcaccess_image_provider.cpp util/vlcaccess_image_provider.hpp \
|
||||
util/covergenerator.cpp \
|
||||
util/covergenerator.hpp \
|
||||
util/imageluminanceextractor.cpp util/imageluminanceextractor.hpp \
|
||||
|
@ -464,6 +465,7 @@ nodist_libqt_plugin_la_SOURCES = \
|
|||
util/base_model.moc.cpp \
|
||||
util/color_scheme_model.moc.cpp \
|
||||
util/color_svg_image_provider.moc.cpp \
|
||||
util/vlcaccess_image_provider.moc.cpp \
|
||||
util/imageluminanceextractor.moc.cpp \
|
||||
util/csdbuttonmodel.moc.cpp \
|
||||
util/keyhelper.moc.cpp \
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
#include "util/flickable_scroll_handler.hpp"
|
||||
#include "util/color_svg_image_provider.hpp"
|
||||
#include "util/effects_image_provider.hpp"
|
||||
#include "util/vlcaccess_image_provider.hpp"
|
||||
#include "util/csdbuttonmodel.hpp"
|
||||
#include "util/vlctick.hpp"
|
||||
#include "util/list_selection_model.hpp"
|
||||
|
@ -144,6 +145,7 @@ MainUI::MainUI(qt_intf_t *p_intf, MainCtx *mainCtx, QWindow* interfaceWindow, Q
|
|||
SingletonRegisterHelper<SystemPalette>::setInstance( new SystemPalette(this) );
|
||||
SingletonRegisterHelper<QmlKeyHelper>::setInstance( new QmlKeyHelper(this) );
|
||||
SingletonRegisterHelper<SVGColorImage>::setInstance( new SVGColorImage(this) );
|
||||
SingletonRegisterHelper<VLCAccessImage>::setInstance( new VLCAccessImage(this) );
|
||||
|
||||
if (m_mainCtx->hasMediaLibrary())
|
||||
{
|
||||
|
@ -174,6 +176,7 @@ bool MainUI::setup(QQmlEngine* engine)
|
|||
|
||||
SingletonRegisterHelper<EffectsImageProvider>::setInstance(new EffectsImageProvider(engine));
|
||||
engine->addImageProvider(QStringLiteral("svgcolor"), new SVGColorImageImageProvider());
|
||||
engine->addImageProvider(QStringLiteral("vlcaccess"), new VLCAccessImageProvider());
|
||||
|
||||
m_component = new QQmlComponent(engine, QStringLiteral("qrc:/main/MainInterface.qml"), QQmlComponent::PreferSynchronous, engine);
|
||||
if (m_component->isLoading())
|
||||
|
@ -239,6 +242,7 @@ void MainUI::registerQMLTypes()
|
|||
qmlRegisterSingletonType<QmlKeyHelper>(uri, versionMajor, versionMinor, "KeyHelper", SingletonRegisterHelper<QmlKeyHelper>::callback);
|
||||
qmlRegisterSingletonType<EffectsImageProvider>(uri, versionMajor, versionMinor, "Effects", SingletonRegisterHelper<EffectsImageProvider>::callback);
|
||||
qmlRegisterSingletonType<SVGColorImage>(uri, versionMajor, versionMinor, "SVGColorImage", SingletonRegisterHelper<SVGColorImage>::callback);
|
||||
qmlRegisterSingletonType<VLCAccessImage>(uri, versionMajor, versionMinor, "VLCAccessImage", SingletonRegisterHelper<VLCAccessImage>::callback);
|
||||
qmlRegisterSingletonType<PlaylistController>(uri, versionMajor, versionMinor, "MainPlaylistController", SingletonRegisterHelper<PlaylistController>::callback);
|
||||
|
||||
qmlRegisterType<DelayEstimator>( uri, versionMajor, versionMinor, "DelayEstimator" );
|
||||
|
|
|
@ -0,0 +1,273 @@
|
|||
/*****************************************************************************
|
||||
* Copyright (C) 2024 VLC authors and VideoLAN
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
|
||||
*****************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
#endif
|
||||
|
||||
#include <vlc_access.h>
|
||||
#include <vlc_stream.h>
|
||||
|
||||
#include "vlcaccess_image_provider.hpp"
|
||||
|
||||
#include "util/asynctask.hpp"
|
||||
#include "qt.hpp"
|
||||
|
||||
#include <QImageReader>
|
||||
#include <QFile>
|
||||
#include <QQmlFile>
|
||||
#include <QUrlQuery>
|
||||
|
||||
#define PATH_KEY "uri"
|
||||
|
||||
namespace {
|
||||
|
||||
class ImageReader : public AsyncTask<QImage>
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief ImageReader
|
||||
* @param device i/o source to read from
|
||||
*
|
||||
* @param requestedSize only taken as hint, the Image is resized with PreserveAspectCrop
|
||||
*
|
||||
* @param radius
|
||||
*/
|
||||
ImageReader(std::unique_ptr<QIODevice> device, QSize requestedSize, VLCAccessImageProvider::ImagePostProcessCb postProcessCb)
|
||||
: device(std::move(device))
|
||||
, requestedSize {requestedSize}
|
||||
, postProcessCb {postProcessCb}
|
||||
{
|
||||
}
|
||||
|
||||
QString errorString() const {
|
||||
return errorStr;
|
||||
}
|
||||
|
||||
QImage execute() override
|
||||
{
|
||||
QImageReader reader;
|
||||
reader.setDevice(device.get());
|
||||
const QSize sourceSize = reader.size();
|
||||
|
||||
if (requestedSize.isValid())
|
||||
reader.setScaledSize(sourceSize.scaled(requestedSize, Qt::KeepAspectRatioByExpanding));
|
||||
|
||||
auto img = reader.read();
|
||||
|
||||
if (img.isNull()) {
|
||||
errorStr = reader.errorString();
|
||||
}
|
||||
|
||||
if (!img.isNull() && postProcessCb)
|
||||
img = postProcessCb(img, requestedSize);
|
||||
|
||||
return img;
|
||||
}
|
||||
|
||||
private:
|
||||
std::unique_ptr<QIODevice> device;
|
||||
QSize requestedSize;
|
||||
QString errorStr;
|
||||
VLCAccessImageProvider::ImagePostProcessCb postProcessCb;
|
||||
};
|
||||
|
||||
|
||||
class VLCAccessImageResponse : public QQuickImageResponse
|
||||
{
|
||||
public:
|
||||
VLCAccessImageResponse(const QUrl& url, const QSize &requestedSize, VLCAccessImageProvider::ImagePostProcessCb postProcessCb = nullptr)
|
||||
: imagePostProcessCb(postProcessCb)
|
||||
{
|
||||
|
||||
std::unique_ptr<QIODevice> device;
|
||||
if (url.scheme().compare(QStringLiteral("qrc"), Qt::CaseInsensitive) == 0)
|
||||
{
|
||||
QString qrcPath = QQmlFile::urlToLocalFileOrQrc(url);
|
||||
device = std::make_unique<QFile>(qrcPath);
|
||||
}
|
||||
else
|
||||
{
|
||||
QUrl fileUrl = url;
|
||||
if (fileUrl.scheme().isEmpty())
|
||||
fileUrl.setScheme("file");
|
||||
device = std::make_unique<VLCIODevice>(fileUrl.toString(QUrl::FullyEncoded));
|
||||
}
|
||||
reader.reset(new ImageReader(std::move(device), requestedSize, postProcessCb));
|
||||
|
||||
connect(reader.get(), &ImageReader::result, this, &VLCAccessImageResponse::handleImageRead);
|
||||
|
||||
reader->start(*QThreadPool::globalInstance());
|
||||
}
|
||||
|
||||
QQuickTextureFactory *textureFactory() const override
|
||||
{
|
||||
return result.isNull() ? nullptr : QQuickTextureFactory::textureFactoryForImage(result);
|
||||
}
|
||||
|
||||
QString errorString() const override
|
||||
{
|
||||
return errorStr;
|
||||
}
|
||||
|
||||
private:
|
||||
void handleImageRead()
|
||||
{
|
||||
result = reader->takeResult();
|
||||
errorStr = reader->errorString();
|
||||
reader.reset();
|
||||
|
||||
emit finished();
|
||||
}
|
||||
|
||||
VLCAccessImageProvider::ImagePostProcessCb imagePostProcessCb;
|
||||
QImage result;
|
||||
TaskHandle<ImageReader> reader;
|
||||
QString errorStr;
|
||||
};
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
//// VLCAccessImageProvider
|
||||
|
||||
VLCAccessImageProvider::VLCAccessImageProvider(VLCAccessImageProvider::ImagePostProcessCb cb)
|
||||
: QQuickAsyncImageProvider()
|
||||
, postProcessCb(cb)
|
||||
{
|
||||
}
|
||||
|
||||
QQuickImageResponse* VLCAccessImageProvider::requestImageResponse(const QString& id, const QSize& requestedSize)
|
||||
{
|
||||
QUrl url {id};
|
||||
QUrlQuery query {url};
|
||||
if (!query.hasQueryItem(PATH_KEY))
|
||||
return nullptr;
|
||||
|
||||
QString vlcurl = query.queryItemValue(PATH_KEY, QUrl::FullyEncoded);
|
||||
return new VLCAccessImageResponse(QUrl::fromEncoded(vlcurl.toUtf8()), requestedSize, postProcessCb);
|
||||
}
|
||||
|
||||
QString VLCAccessImageProvider::wrapUri(QString path)
|
||||
{
|
||||
QUrlQuery query;
|
||||
query.addQueryItem(PATH_KEY, path);
|
||||
return QStringLiteral("image://vlcaccess/?") + query.toString(QUrl::FullyEncoded);
|
||||
}
|
||||
|
||||
//// VLCImageAccess
|
||||
|
||||
VLCAccessImage::VLCAccessImage(QObject* parent)
|
||||
: QObject(parent)
|
||||
{}
|
||||
|
||||
QString VLCAccessImage::uri(QString path)
|
||||
{
|
||||
return VLCAccessImageProvider::wrapUri(path);
|
||||
}
|
||||
|
||||
//// VLCIODevice
|
||||
|
||||
VLCIODevice::VLCIODevice(const QString& filename, QObject* parent)
|
||||
: QIODevice(parent)
|
||||
, m_filename(filename)
|
||||
{
|
||||
}
|
||||
|
||||
VLCIODevice::~VLCIODevice()
|
||||
{
|
||||
close();
|
||||
}
|
||||
|
||||
bool VLCIODevice::open(OpenMode mode)
|
||||
{
|
||||
//we only support reading
|
||||
if (mode & QIODevice::OpenModeFlag::WriteOnly)
|
||||
return false;
|
||||
|
||||
m_stream = vlc_access_NewMRL(nullptr, qtu(m_filename));
|
||||
if (m_stream == nullptr)
|
||||
return false;
|
||||
|
||||
return QIODevice::open(mode);
|
||||
}
|
||||
|
||||
bool VLCIODevice::isSequential() const
|
||||
{
|
||||
assert(m_stream);
|
||||
//some access (like http) will perform really poorly with the way
|
||||
//Qt uses the QIODevice (lots of seeks)
|
||||
//return !vlc_stream_CanSeek(m_stream);
|
||||
return true;
|
||||
}
|
||||
|
||||
void VLCIODevice::close()
|
||||
{
|
||||
if (!m_stream)
|
||||
return;
|
||||
vlc_stream_Delete(m_stream);
|
||||
m_stream = nullptr;
|
||||
}
|
||||
|
||||
qint64 VLCIODevice::pos() const
|
||||
{
|
||||
assert(m_stream);
|
||||
return vlc_stream_Tell(m_stream);
|
||||
}
|
||||
|
||||
qint64 VLCIODevice::size() const
|
||||
{
|
||||
assert(m_stream);
|
||||
uint64_t streamSize;
|
||||
bool ret = vlc_stream_GetSize(m_stream, &streamSize);
|
||||
if (!ret)
|
||||
return -1;
|
||||
return static_cast<qint64>(streamSize);
|
||||
}
|
||||
|
||||
bool VLCIODevice::seek(qint64 pos)
|
||||
{
|
||||
assert(m_stream);
|
||||
QIODevice::seek(pos);
|
||||
if (pos < 0)
|
||||
return false;
|
||||
return vlc_stream_Seek(m_stream, pos) == VLC_SUCCESS;
|
||||
}
|
||||
|
||||
bool VLCIODevice::atEnd() const
|
||||
{
|
||||
assert(m_stream);
|
||||
return vlc_stream_Eof(m_stream);
|
||||
}
|
||||
|
||||
bool VLCIODevice::reset()
|
||||
{
|
||||
assert(m_stream);
|
||||
return vlc_stream_Seek(m_stream, 0) == VLC_SUCCESS;
|
||||
}
|
||||
|
||||
qint64 VLCIODevice::readData(char* data, qint64 maxlen)
|
||||
{
|
||||
assert(m_stream);
|
||||
return vlc_stream_Read(m_stream, data, maxlen);
|
||||
}
|
||||
|
||||
qint64 VLCIODevice::writeData(const char*, qint64)
|
||||
{
|
||||
assert(m_stream);
|
||||
return -1;
|
||||
}
|
|
@ -0,0 +1,102 @@
|
|||
/*****************************************************************************
|
||||
* Copyright (C) 2024 VLC authors and VideoLAN
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
|
||||
*****************************************************************************/
|
||||
#ifndef VLCACCESSIMAGEPROVIDER_HPP
|
||||
#define VLCACCESSIMAGEPROVIDER_HPP
|
||||
|
||||
#include <QObject>
|
||||
#include <QQuickAsyncImageProvider>
|
||||
#include <QString>
|
||||
#include <QIODevice>
|
||||
|
||||
typedef struct stream_t stream_t;
|
||||
|
||||
/**
|
||||
* VLCIODevice is a QIODevice based on vlc_access
|
||||
*/
|
||||
class VLCIODevice : public QIODevice
|
||||
{
|
||||
public:
|
||||
VLCIODevice(const QString &filename, QObject *parent = nullptr);
|
||||
|
||||
virtual ~VLCIODevice();
|
||||
|
||||
public:
|
||||
bool open(QIODevice::OpenMode mode) override;
|
||||
|
||||
bool isSequential() const override;
|
||||
|
||||
void close() override;
|
||||
|
||||
qint64 pos() const override;
|
||||
|
||||
qint64 size() const override;
|
||||
|
||||
bool seek(qint64 pos) override;
|
||||
|
||||
bool atEnd() const override;
|
||||
|
||||
bool reset() override;
|
||||
|
||||
protected:
|
||||
qint64 readData(char *data, qint64 maxlen) override;
|
||||
|
||||
qint64 writeData(const char*, qint64) override;
|
||||
|
||||
private:
|
||||
QString m_filename;
|
||||
stream_t* m_stream = nullptr;
|
||||
};
|
||||
|
||||
class VLCAccessImageProvider: public QQuickAsyncImageProvider
|
||||
{
|
||||
public:
|
||||
typedef std::function<QImage (QImage&, const QSize &)> ImagePostProcessCb;
|
||||
|
||||
VLCAccessImageProvider(ImagePostProcessCb cb = nullptr);
|
||||
|
||||
QQuickImageResponse* requestImageResponse(const QString &id, const QSize &requestedSize) override;
|
||||
|
||||
static QString wrapUri(QString path);
|
||||
|
||||
private:
|
||||
ImagePostProcessCb postProcessCb;
|
||||
};
|
||||
|
||||
class VLCAccessImage : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
VLCAccessImage(QObject* parent = nullptr);
|
||||
|
||||
/**
|
||||
* @brief adapt @path to open it using
|
||||
* @param path to the artwork
|
||||
*
|
||||
* sample usage:
|
||||
*
|
||||
* @code{qml}
|
||||
* Image {
|
||||
* src: VLCImageAccess.uri("file:///path/to/assert.svg")
|
||||
* }
|
||||
* @code
|
||||
*
|
||||
*/
|
||||
Q_INVOKABLE QString uri(QString path);
|
||||
|
||||
};
|
||||
|
||||
#endif // VLCACCESSIMAGEPROVIDER_HPP
|
Loading…
Reference in New Issue