Commit cac8cce3 authored by Jean-Baptiste Mardelle's avatar Jean-Baptiste Mardelle
Browse files

Use small size profile for faster thumbnail generation, restore file watching...

Use small size profile for faster thumbnail generation, restore file watching and fix bin clip losing effects on reload
parent e8b5e646
......@@ -1033,16 +1033,7 @@ void Bin::slotReloadClip()
}
}
}
QDomDocument doc;
QDomElement xml = currentItem->toXml(doc);
qCDebug(KDENLIVE_LOG) << "*****************\n" << doc.toString() << "\n******************";
if (!xml.isNull()) {
currentItem->setClipStatus(AbstractProjectItem::StatusWaiting);
// We need to set a temporary id before all outdated producers are replaced;
// TODO refac
// m_doc->getFileProperties(xml, currentItem->AbstractProjectItem::clipId(), 150, true);
pCore->jobManager()->startJob<LoadJob>({currentItem->AbstractProjectItem::clipId()}, -1, QString(), xml);
}
currentItem->reloadProducer(false);
}
}
}
......@@ -1799,6 +1790,16 @@ void Bin::slotRemoveInvalidClip(const QString &id, bool replace, const QString &
emit requesteInvalidRemoval(id, clip->url(), errorMessage);
}
void Bin::addWatchFile(const QString &binId, const QString &url)
{
m_fileWatcher.addFile(binId, url);
}
void Bin::removeWatchFile(const QString &binId, const QString &url)
{
m_fileWatcher.removeFile(binId, url);
}
// TODO refac cleanup
/*
void Bin::slotProducerReady(const requestClipInfo &info, std::shared_ptr<Mlt::Producer> producer)
......
......@@ -288,6 +288,8 @@ public:
/** @brief Save a clip zone as MLT playlist */
void saveZone(const QStringList &info, const QDir &dir);
QVariantList audioFrameCache(const QString &id);
void addWatchFile(const QString &binId, const QString &url);
void removeWatchFile(const QString &binId, const QString &url);
// TODO refac: remove this and call directly the function in ProjectItemModel
void cleanup();
......
......@@ -77,6 +77,9 @@ ProjectClip::ProjectClip(const QString &id, const QIcon &thumb, std::shared_ptr<
} else {
m_thumbnail = thumb;
}
if (m_clipType == ClipType::AV || m_clipType == ClipType::Audio || m_clipType == ClipType::Image || m_clipType == ClipType::Video || m_clipType == ClipType::Playlist || m_clipType == ClipType::TextTemplate) {
pCore->bin()->addWatchFile(id, clipUrl());
}
// Make sure we have a hash for this clip
hash();
connect(m_markerModel.get(), &MarkerListModel::modelChanged, [&]() { setProducerProperty(QStringLiteral("kdenlive:markers"), m_markerModel->toJson()); });
......@@ -135,6 +138,9 @@ std::shared_ptr<ProjectClip> ProjectClip::construct(const QString &id, const QDo
ProjectClip::~ProjectClip()
{
// controller is deleted in bincontroller
if (m_clipType == ClipType::AV || m_clipType == ClipType::Audio || m_clipType == ClipType::Image || m_clipType == ClipType::Video || m_clipType == ClipType::Playlist || m_clipType == ClipType::TextTemplate) {
pCore->bin()->removeWatchFile(clipId(), clipUrl());
}
m_thumbMutex.lock();
m_requestedThumbs.clear();
m_thumbMutex.unlock();
......@@ -290,6 +296,7 @@ void ProjectClip::reloadProducer(bool refreshOnly)
// In that case, we only want a new thumbnail.
// We thus set up a thumb job. We must make sure that there is no pending LOADJOB
// Clear cache first
m_thumbsProducer.reset();
ThumbnailCache::get()->invalidateThumbsForClip(clipId());
pCore->jobManager()->startJob<ThumbJob>({clipId()}, loadjobId, QString(), 150, -1, true, true);
......@@ -298,8 +305,9 @@ void ProjectClip::reloadProducer(bool refreshOnly)
QDomDocument doc;
QDomElement xml = toXml(doc);
if (!xml.isNull()) {
m_thumbsProducer.reset();
ThumbnailCache::get()->invalidateThumbsForClip(clipId());
int loadJob = pCore->jobManager()->startJob<LoadJob>({clipId()}, -1, QString(), xml);
int loadJob = pCore->jobManager()->startJob<LoadJob>({clipId()}, loadjobId, QString(), xml);
pCore->jobManager()->startJob<ThumbJob>({clipId()}, loadJob, QString(), 150, -1, true, true);
}
}
......@@ -346,6 +354,7 @@ bool ProjectClip::setProducer(std::shared_ptr<Mlt::Producer> producer, bool repl
{
Q_UNUSED(replaceProducer)
qDebug() << "################### ProjectClip::setproducer";
QMutexLocker locker(&m_producerMutex);
updateProducer(std::move(producer));
connectEffectStack();
......@@ -374,6 +383,9 @@ bool ProjectClip::setProducer(std::shared_ptr<Mlt::Producer> producer, bool repl
}
// Make sure we have a hash for this clip
getFileHash();
if (m_clipType == ClipType::AV || m_clipType == ClipType::Audio || m_clipType == ClipType::Image || m_clipType == ClipType::Video || m_clipType == ClipType::Playlist || m_clipType == ClipType::TextTemplate) {
pCore->bin()->addWatchFile(clipId(), clipUrl());
}
// set parent again (some info need to be stored in producer)
updateParent(parentItem().lock());
return true;
......@@ -392,16 +404,16 @@ std::shared_ptr<Mlt::Producer> ProjectClip::thumbProducer()
if (!prod->is_valid()) {
return nullptr;
}
Clip clip(*prod.get());
if (KdenliveSettings::gpu_accel()) {
//TODO: when the original producer changes, we must reload this thumb producer
Clip clip(*prod.get());
m_thumbsProducer = std::make_shared<Mlt::Producer>(clip.softClone(ClipController::getPassPropertiesList()));
Mlt::Filter scaler(*prod->profile(), "swscale");
Mlt::Filter converter(*prod->profile(), "avcolor_space");
m_thumbsProducer->attach(scaler);
m_thumbsProducer->attach(converter);
} else {
m_thumbsProducer = std::make_shared<Mlt::Producer>(new Mlt::Producer(prod.get()));
m_thumbsProducer = cloneProducer(pCore->thumbProfile());
}
return m_thumbsProducer;
}
......@@ -442,7 +454,7 @@ std::shared_ptr<Mlt::Producer> ProjectClip::timelineProducer(PlaylistState::Clip
return std::shared_ptr<Mlt::Producer>(normalProd->cut());
}
std::shared_ptr<Mlt::Producer> ProjectClip::cloneProducer()
std::shared_ptr<Mlt::Producer> ProjectClip::cloneProducer(Mlt::Profile *destProfile)
{
Mlt::Consumer c(*m_masterProducer->profile(), "xml", "string");
Mlt::Service s(m_masterProducer->get_service());
......@@ -462,7 +474,7 @@ std::shared_ptr<Mlt::Producer> ProjectClip::cloneProducer()
s.set("ignore_points", ignore);
}
const QByteArray clipXml = c.get("string");
std::shared_ptr<Mlt::Producer> prod(new Mlt::Producer(*m_masterProducer->profile(), "xml-string", clipXml.constData()));
std::shared_ptr<Mlt::Producer> prod(new Mlt::Producer(destProfile ? *destProfile : *m_masterProducer->profile(), "xml-string", clipXml.constData()));
return prod;
}
......
......@@ -189,7 +189,7 @@ public:
/** @brief Returns a list of all timeline clip ids for this bin clip */
QList<int> timelineInstances() const;
std::shared_ptr<Mlt::Producer> timelineProducer(PlaylistState::ClipState state = PlaylistState::Original, int track = 1);
std::shared_ptr<Mlt::Producer> cloneProducer();
std::shared_ptr<Mlt::Producer> cloneProducer(Mlt::Profile *destProfile = nullptr);
void updateTimelineClips(QVector<int> roles);
protected:
......
......@@ -48,6 +48,7 @@ Core::Core()
, m_monitorManager(nullptr)
, m_binWidget(nullptr)
, m_library(nullptr)
, m_thumbProfile(nullptr)
{
}
......@@ -302,6 +303,7 @@ bool Core::setCurrentProfile(const QString &profilePath)
}
if (ProfileRepository::get()->profileExists(profilePath)) {
m_currentProfile = profilePath;
m_thumbProfile.reset();
// inform render widget
m_mainWindow->updateRenderWidgetProfile();
return true;
......@@ -557,3 +559,15 @@ void Core::showClipKeyframes(ObjectId id, bool enable)
m_mainWindow->getCurrentTimeline()->controller()->showCompositionKeyframes(id.second, enable);
}
}
Mlt::Profile *Core::thumbProfile()
{
if (!m_thumbProfile) {
m_thumbProfile = std::unique_ptr<Mlt::Profile>(new Mlt::Profile(m_currentProfile.toStdString().c_str()));
m_thumbProfile->set_height(200);
int width = 200 * m_thumbProfile->dar();
width += width % 8;
m_thumbProfile->set_width(width);
}
return m_thumbProfile.get();
}
......@@ -35,6 +35,7 @@ class ProjectManager;
namespace Mlt {
class Repository;
class Profile;
}
#define EXIT_RESTART (42)
......@@ -164,6 +165,7 @@ public:
void updateItemModel(ObjectId id, const QString &service);
/** Show / hide keyframes for a timeline clip */
void showClipKeyframes(ObjectId id, bool enable);
Mlt::Profile *thumbProfile();
private:
explicit Core();
......@@ -184,7 +186,7 @@ private:
QString m_currentProfile;
QString m_profile;
std::unique_ptr<Mlt::Profile> m_thumbProfile;
bool m_guiConstructed = false;
signals:
......
/***************************************************************************
* Copyright (C) 2017 by Nicolas Carion *
* This file is part of Kdenlive. See www.kdenlive.org. *
......
......@@ -306,6 +306,7 @@ void ClipController::updateProducer(const std::shared_ptr<Mlt::Producer> &produc
if (!m_masterProducer->is_valid()) {
qCDebug(KDENLIVE_LOG) << "// WARNING, USING INVALID PRODUCER";
} else {
m_effectStack->resetService(m_masterProducer);
// URL and name shoule not be updated otherwise when proxying a clip we cannot find back the original url
/*m_url = QUrl::fromLocalFile(m_masterProducer->get("resource"));
if (m_url.isValid()) {
......
......@@ -36,7 +36,7 @@
#include "recmanager.h"
#include "scopes/monitoraudiolevel.h"
#include "timeline/abstractclipitem.h"
#include "timeline/clip.h"
#include "mltcontroller/clip.h"
#include "timeline/transitionhandler.h"
#include "timeline2/model/snapmodel.hpp"
#include "transitions/transitionsrepository.hpp"
......
......@@ -174,6 +174,7 @@ const QByteArray Clip::xml()
c.set("time_format", "frames");
c.set("no_meta", 1);
c.set("no_root", 1);
c.set("no_profile", 1);
c.set("root", "/");
c.set("store", "kdenlive");
c.start();
......@@ -186,16 +187,7 @@ const QByteArray Clip::xml()
Mlt::Producer *Clip::clone()
{
QByteArray prodXml = xml();
// HACK: currently the MLT xml producer, when parsing a <profile>, does change the global profile accordingly.
// causing crash on threaded calls. To avoid this, we discard the profile info from our xml
QDomDocument doc;
doc.setContent(prodXml, true);
QDomNodeList profiles = doc.documentElement().elementsByTagName("profile");
if (!profiles.isEmpty()) {
QDomNode profile = profiles.item(0);
doc.documentElement().removeChild(profile);
}
Mlt::Producer *clone = new Mlt::Producer(*m_producer.profile(), "xml-string", doc.toByteArray().constData());
Mlt::Producer *clone = new Mlt::Producer(*m_producer.profile(), "xml-string", prodXml);
return clone;
}
......
......@@ -30,13 +30,8 @@
ThumbnailProvider::ThumbnailProvider()
: QQuickImageProvider(QQmlImageProviderBase::Image, QQmlImageProviderBase::ForceAsynchronousImageLoading)
, m_profile(pCore->getCurrentProfilePath().toUtf8().constData())
//, m_profile(pCore->getCurrentProfilePath().toUtf8().constData())
{
int width = 180 * m_profile.dar();
width += width % 8;
m_profile.set_height(180);
m_profile.set_width(width);
m_producers.setMaxCost(6);
}
ThumbnailProvider::~ThumbnailProvider()
......@@ -136,18 +131,21 @@ QString ThumbnailProvider::cacheKey(Mlt::Properties &properties, const QString &
QImage ThumbnailProvider::makeThumbnail(std::shared_ptr<Mlt::Producer>producer, int frameNumber, const QSize &requestedSize)
{
Q_UNUSED(requestedSize)
producer->seek(frameNumber);
Mlt::Frame *frame = producer->get_frame();
QScopedPointer<Mlt::Frame> frame(producer->get_frame());
if (frame == nullptr || !frame->is_valid()) {
return QImage();
}
mlt_image_format format = mlt_image_rgb24a;
int ow = 0;
int oh = 0;
QImage result;
const uchar *imagedata = frame->get_image(format, ow, oh);
if (imagedata) {
result = QImage(ow, oh, QImage::Format_RGBA8888);
QImage result(ow, oh, QImage::Format_RGBA8888);
memcpy(result.bits(), imagedata, (unsigned)(ow * oh * 4));
if (!result.isNull()) {
return result;
}
}
delete frame;
return result;
return QImage();
}
......@@ -37,7 +37,6 @@ public:
private:
QString cacheKey(Mlt::Properties &properties, const QString &service, const QString &resource, const QString &hash, int frameNumber);
QImage makeThumbnail(std::shared_ptr<Mlt::Producer> producer, int frameNumber, const QSize &requestedSize);
Mlt::Profile m_profile;
QCache<int, Mlt::Producer> m_producers;
};
......
......@@ -37,7 +37,6 @@ GeometryWidget::GeometryWidget(Monitor *monitor, QPair<int, int> range, const QR
, m_monitor(monitor)
{
Q_UNUSED(useRatioLock)
setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Maximum);
auto *layout = new QVBoxLayout(this);
layout->setContentsMargins(0, 0, 0, 0);
......
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