Commit 9b24305d authored by Hugo Beauzée-Luyssen's avatar Hugo Beauzée-Luyssen

Rework thumbnail generation

- Add missing headers
- Let the framework handle background generation of the thumbnails
- Let the framework handle the caching
- Use Image instead of Pixmap, since the later might not be usable
outside of UI thread
parent b900657e
......@@ -37,7 +37,6 @@ vlmc_SOURCES = \
src/Workflow/Helper.cpp \
src/Workflow/MainWorkflow.cpp \
src/Workflow/SequenceWorkflow.cpp \
src/Workflow/ThumbnailWorker.cpp \
$(NULL)
vlmc_SOURCES += \
......@@ -100,7 +99,6 @@ vlmc_SOURCES += \
nodist_vlmc_SOURCES = \
src/Media/Clip.moc.cpp \
src/Workflow/SequenceWorkflow.moc.cpp \
src/Workflow/ThumbnailWorker.moc.cpp \
src/Services/YouTube/YouTubeService.moc.cpp \
src/EffectsEngine/EffectHelper.moc.cpp \
src/Workflow/Helper.moc.cpp \
......
......@@ -78,10 +78,6 @@ Rectangle {
effectsItem.text = str;
}
function updateThumbnail( pos ) {
thumbnailSource = "image://thumbnail/" + libraryUuid + "/" + pos;
}
function resizeLinkedClips( oldPos, oldBegin, oldEnd ) {
if ( !linkedClip )
return;
......@@ -204,11 +200,7 @@ Rectangle {
if ( uuid === "videoUuid" || uuid === "audioUuid" )
return;
if ( thumbnailProvider.hasImage( uuid, begin ) )
updateThumbnail( begin );
else
workflow.takeThumbnail( uuid, begin );
thumbnailSource = "image://thumbnail/" + libraryUuid + "/0";
}
Component.onDestruction: {
......@@ -257,6 +249,7 @@ Rectangle {
anchors.bottomMargin: 4
fillMode: Image.PreserveAspectFit
visible: width < clip.width
asynchronous: true
}
MouseArea {
......
/*****************************************************************************
* ThumbnailImageProvider.cpp
*****************************************************************************
* Copyright (C) 2008-2016 VideoLAN
*
* Authors: Yikei Lu <luyikei.qmltu@gmail.com>
* Hugo Beauzée-Luyssen <hugo@beauzee.fr>
*
* 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.
*****************************************************************************/
#include "ThumbnailImageProvider.h"
#include "Workflow/MainWorkflow.h"
#include "Library/Library.h"
#include "Media/Clip.h"
#include "Media/Media.h"
#include "Main/Core.h"
#include "Tools/VlmcDebug.h"
#include "Workflow/MainWorkflow.h"
ThumbnailImageProvider::ThumbnailImageProvider()
: QQuickImageProvider( QQuickImageProvider::Pixmap )
: QQuickImageProvider( QQuickImageProvider::Image )
{
connect( Core::instance()->workflow(), &MainWorkflow::thumbnailUpdated, this, [this]
( const QString& uuid, quint32 pos, const QPixmap& pixmap )
{
auto id = uuid + "/" + QString::number( pos );
auto it = m_pixMap.find( id );
if ( it == m_pixMap.end() )
m_pixMap.insert( id, pixmap );
emit imageReady( uuid, pos );
}, Qt::DirectConnection );
}
QPixmap
ThumbnailImageProvider::requestPixmap( const QString& id, QSize* size, const QSize& requestedSize )
QImage
ThumbnailImageProvider::requestImage( const QString& id, QSize* size, const QSize& requestedSize )
{
QString tmp = id;
tmp.replace( "%7B", "{" );
tmp.replace( "%7D", "}" );
auto it = m_pixMap.find( tmp );
if ( it == m_pixMap.end() )
{
*size = QSize( requestedSize.width(), requestedSize.height() );
return QPixmap( requestedSize );
}
auto pixmap = it.value();
*size = pixmap.size();
if ( requestedSize.isValid() == true )
return pixmap.scaled( requestedSize );
return pixmap;
}
bool
ThumbnailImageProvider::hasImage( const QString& uuid, quint32 pos )
{
return m_pixMap.find( uuid + "/" + QString::number( pos ) ) != m_pixMap.end();
auto infos = tmp.split( '/' );
auto libraryUuid = infos[0];
auto clip = Core::instance()->library()->clip( libraryUuid );
Backend::MLT::MLTInput input( qPrintable( clip->media()->mrl() ) );
input.setPosition( infos[0].toLongLong() );
size->setWidth( input.width() );
size->setHeight( input.height() );
auto width = requestedSize.width() > 0 ? requestedSize.width() : size->width();
auto height = requestedSize.height() > 0 ? requestedSize.height() : size->height();
auto image = input.image( width, height );
QImage qImg( image, width, height, QImage::Format_RGBA8888,
[]( void* ptr ){ delete[] (uint8_t*)ptr; } );
return qImg;
}
/*****************************************************************************
* ThumbnailImageProvider.h
*****************************************************************************
* Copyright (C) 2008-2016 VideoLAN
*
* Authors: Yikei Lu <luyikei.qmltu@gmail.com>
* Hugo Beauzée-Luyssen <hugo@beauzee.fr>
*
* 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 THUMBNAILIMAGEPROVIDER_H
#define THUMBNAILIMAGEPROVIDER_H
#include <QMap>
#include <QQuickImageProvider>
class ThumbnailImageProvider : public QObject, public QQuickImageProvider
......@@ -11,17 +33,7 @@ class ThumbnailImageProvider : public QObject, public QQuickImageProvider
public:
ThumbnailImageProvider();
virtual QPixmap requestPixmap( const QString& id, QSize* size, const QSize& requestedSize ) override;
public slots:
bool hasImage( const QString& uuid, quint32 pos );
signals:
void imageReady( const QString& uuid, quint32 pos );
private:
// uuid/pos, pixmap
QMap<QString, QPixmap> m_pixMap;
virtual QImage requestImage( const QString& id, QSize* size, const QSize& requestedSize ) override;
};
#endif // THUMBNAILIMAGEPROVIDER_H
......@@ -645,13 +645,5 @@ Rectangle {
isCutMode = false;
}
}
Connections {
target: thumbnailProvider
onImageReady: {
var clipItem = findClipItem( uuid );
clipItem.updateThumbnail( clipItem.begin );
}
}
}
......@@ -50,7 +50,6 @@
#include "Tools/RendererEventWatcher.h"
#include "Tools/OutputEventWatcher.h"
#include "Workflow/Types.h"
#include "ThumbnailWorker.h"
#include <QMutex>
......@@ -210,6 +209,7 @@ MainWorkflow::clipInfo( const QString& uuid )
auto clip = c->clip;
auto h = clip->toVariant().toHash();
h["uuid"] = uuid;
vlmcWarning() << "library UUID: " << h["libraryUuid"];
h["length"] = (qint64)( clip->input()->length() );
h["name"] = clip->media()->title();
h["audio"] = c->isAudio;
......@@ -308,26 +308,6 @@ MainWorkflow::addEffect( const QString &clipUuid, const QString &effectId )
return QStringLiteral( "" );
}
void
MainWorkflow::takeThumbnail( const QString& uuid, quint32 pos )
{
vlmcDebug() << "Generating thumbnail for" << uuid;
// We need to fetch the clip from the library. This clip is being added to the library
// and doesn't have an instance ID yet
auto swClip = m_sequenceWorkflow->clip( uuid );
auto clip = swClip->clip;
auto worker = new ThumbnailWorker( uuid, clip->media()->mrl(),
pos, clip->input()->width(), clip->input()->height() );
auto t = new QThread;
worker->moveToThread( t );
connect( t, &QThread::started, worker, &ThumbnailWorker::run );
connect( worker, &ThumbnailWorker::imageReady, this, &MainWorkflow::thumbnailUpdated, Qt::DirectConnection );
connect( worker, &ThumbnailWorker::imageReady, t, &QThread::quit );
connect( t, &QThread::finished, worker, &ThumbnailWorker::deleteLater );
connect( t, &QThread::finished, t, &QThread::deleteLater );
t->start();
}
bool
MainWorkflow::startRenderToFile( const QString &outputFileName, quint32 width, quint32 height,
double fps, const QString &ar, quint32 vbitrate, quint32 abitrate,
......
......@@ -150,9 +150,6 @@ class MainWorkflow : public QObject
Q_INVOKABLE
QString addEffect( const QString& clipUuid, const QString& effectId );
Q_INVOKABLE
void takeThumbnail( const QString& uuid, quint32 pos );
bool startRenderToFile( const QString& outputFileName, quint32 width, quint32 height,
double fps, const QString& ar, quint32 vbitrate, quint32 abitrate,
quint32 nbChannels, quint32 sampleRate );
......@@ -179,7 +176,6 @@ class MainWorkflow : public QObject
std::unique_ptr<Commands::AbstractUndoStack> m_undoStack;
std::shared_ptr<SequenceWorkflow> m_sequenceWorkflow;
public slots:
/**
* \brief Clear the workflow.
......@@ -250,8 +246,6 @@ class MainWorkflow : public QObject
void clipUnlinked( const QString& uuidA, const QString& uuidB );
void effectsUpdated( const QString& clipUuid );
void thumbnailUpdated( const QString& uuid, quint32 pos, const QPixmap& pixmap );
};
#endif // MAINWORKFLOW_H
#include "ThumbnailWorker.h"
#include <QPixmap>
#include <QUuid>
#include "Backend/MLT/MLTInput.h"
ThumbnailWorker::ThumbnailWorker( const QString& uuid, const QString& filePath,
qint64 pos, quint32 width, quint32 height, QObject* parent )
: QObject( parent )
, m_uuid( uuid )
, m_filePath( filePath )
, m_pos( pos )
, m_width( width )
, m_height( height )
{
}
void
ThumbnailWorker::run()
{
Backend::MLT::MLTInput input( qPrintable( m_filePath ) );
input.setPosition( m_pos );
auto image = input.image( m_width, m_height );
QImage qImg( image, m_width, m_height,
QImage::Format_RGBA8888, []( void* buf ){ delete[] (uchar*) buf; } );
auto qPix = QPixmap::fromImage( qImg );
// Use Qt::DirectConnection or the pixmap will be deleted!
emit imageReady( m_uuid, m_pos, qPix );
}
#ifndef THUMBNAILWORKER_H
#define THUMBNAILWORKER_H
#include <QObject>
class QPixmap;
class ThumbnailWorker : public QObject
{
Q_OBJECT
public:
explicit ThumbnailWorker( const QString& uuid, const QString& filePath,
qint64 pos, quint32 width, quint32 height , QObject* parent = 0 );
signals:
void imageReady( const QString& uuid, qint64 pos, const QPixmap& pixmap );
public slots:
void run();
private:
QString m_uuid;
QString m_filePath;
qint64 m_pos;
quint32 m_width;
quint32 m_height;
};
#endif // THUMBNAILWORKER_H
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment