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

Cleanup, fix memleaks and crash with effect compare

parent 69de64f0
......@@ -779,7 +779,6 @@ QDockWidget *Bin::clipPropertiesDock()
void Bin::abortOperations()
{
blockSignals(true);
abortAudioThumbs();
if (m_propertiesPanel) {
for (QWidget *w : m_propertiesPanel->findChildren<ClipPropertiesController *>()) {
delete w;
......@@ -790,62 +789,6 @@ void Bin::abortOperations()
blockSignals(false);
}
void Bin::abortAudioThumbs()
{
// TODO refac
/*
if (!m_audioThumbsThread.isRunning()) {
return;
}
if (!m_processingAudioThumb.isEmpty()) {
std::shared_ptr<ProjectClip> clip = m_itemModel->getClipByBinID(m_processingAudioThumb);
if (clip) {
clip->abortAudioThumbs();
}
}
m_audioThumbMutex.lock();
for (const QString &id : m_audioThumbsList) {
std::shared_ptr<ProjectClip> clip = m_itemModel->getClipByBinID(id);
if (clip) {
clip->setJobStatus(AbstractClipJob::THUMBJOB, JobDone, 0);
}
}
m_audioThumbsList.clear();
m_audioThumbMutex.unlock();
m_audioThumbsThread.waitForFinished();
*/
}
void Bin::slotCreateAudioThumbs()
{
// TODO refac
/*
int max = m_audioThumbsList.count();
int count = 0;
m_processedAudio = 0;
while (!m_audioThumbsList.isEmpty()) {
m_audioThumbMutex.lock();
max = qMax(max, m_audioThumbsList.count());
m_processingAudioThumb = m_audioThumbsList.takeFirst();
count++;
m_audioThumbMutex.unlock();
std::shared_ptr<ProjectClip> clip = m_itemModel->getClipByBinID(m_processingAudioThumb);
if (clip) {
clip->slotCreateAudioThumbs();
m_processedAudio += (int)clip->duration().ms();
} else {
qDebug() << "// Trying to create audio thumbs for unknown clip: " << m_processingAudioThumb;
}
}
m_audioThumbMutex.lock();
m_processingAudioThumb.clear();
m_processedAudio = 0;
m_audioDuration = 0;
m_audioThumbMutex.unlock();
emitMessage(i18n("Audio thumbnails done"), 100, OperationCompletedMessage);
*/
}
bool Bin::eventFilter(QObject *obj, QEvent *event)
{
if (event->type() == QEvent::MouseButtonRelease) {
......
......@@ -302,7 +302,6 @@ private slots:
void slotGotFocus();
/** @brief Rename a Bin Item. */
void slotRenameItem();
void slotCreateAudioThumbs();
void doRefreshPanel(const QString &id);
/** @brief Send audio thumb data to monitor for display. */
void slotSendAudioThumb(const QString &id);
......@@ -348,7 +347,6 @@ public slots:
**/
void slotGetCurrentProjectImage(const QString &clipId, bool request);
void slotExpandUrl(const ItemInfo &info, const QString &url, QUndoCommand *command);
void abortAudioThumbs();
/** @brief Abort all ongoing operations to prepare close. */
void abortOperations();
void doDisplayMessage(const QString &text, KMessageWidget::MessageType type, const QList<QAction *> &actions = QList<QAction *>());
......
......@@ -32,7 +32,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "jobs/thumbjob.hpp"
#include "kdenlivesettings.h"
#include "lib/audio/audioStreamInfo.h"
#include "mltcontroller/clip.h"
#include "mltcontroller/clipcontroller.h"
#include "mltcontroller/clippropertiescontroller.h"
#include "model/markerlistmodel.hpp"
......@@ -459,8 +458,7 @@ std::shared_ptr<Mlt::Producer> ProjectClip::thumbProducer()
}
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()));
m_thumbsProducer = softClone(ClipController::getPassPropertiesList());
Mlt::Filter scaler(*prod->profile(), "swscale");
Mlt::Filter converter(*prod->profile(), "avcolor_space");
m_thumbsProducer->attach(scaler);
......@@ -726,6 +724,44 @@ std::shared_ptr<Mlt::Producer> ProjectClip::cloneProducer(Mlt::Profile *destProf
return prod;
}
std::shared_ptr<Mlt::Producer> ProjectClip::cloneProducer(std::shared_ptr<Mlt::Producer> producer)
{
Mlt::Consumer c(*producer->profile(), "xml", "string");
Mlt::Service s(producer->get_service());
int ignore = s.get_int("ignore_points");
if (ignore) {
s.set("ignore_points", 0);
}
c.connect(s);
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();
if (ignore) {
s.set("ignore_points", ignore);
}
const QByteArray clipXml = c.get("string");
std::shared_ptr<Mlt::Producer> prod(new Mlt::Producer(*producer->profile(), "xml-string", clipXml.constData()));
if (strcmp(prod->get("mlt_service"), "avformat") == 0) {
prod->set("mlt_service", "avformat-novalidate");
}
return prod;
}
std::shared_ptr<Mlt::Producer> ProjectClip::softClone(const char *list)
{
QString service = QString::fromLatin1(m_masterProducer->get("mlt_service"));
QString resource = QString::fromLatin1(m_masterProducer->get("resource"));
std::shared_ptr<Mlt::Producer> clone(new Mlt::Producer(*m_masterProducer->profile(), service.toUtf8().constData(), resource.toUtf8().constData()));
Mlt::Properties original(m_masterProducer->get_properties());
Mlt::Properties cloneProps(clone->get_properties());
cloneProps.pass_list(original, list);
return clone;
}
bool ProjectClip::isReady() const
{
return m_clipStatus == StatusReady;
......
......@@ -214,6 +214,8 @@ public:
PlaylistState::ClipState state);
std::shared_ptr<Mlt::Producer> cloneProducer(Mlt::Profile *destProfile = nullptr);
static std::shared_ptr<Mlt::Producer> cloneProducer(std::shared_ptr<Mlt::Producer> producer);
std::shared_ptr<Mlt::Producer> softClone(const char *list);
void updateTimelineClips(QVector<int> roles);
protected:
......
......@@ -714,6 +714,20 @@ std::vector<QString> ProjectItemModel::getAllClipIds() const
return result;
}
QStringList ProjectItemModel::getClipByUrl(const QFileInfo &url) const
{
QStringList result;
for (const auto &clip : m_allItems) {
auto c = std::static_pointer_cast<AbstractProjectItem>(clip.second.lock());
if (c->itemType() == AbstractProjectItem::ClipItem) {
if (QFileInfo(std::static_pointer_cast<ProjectClip>(c)->clipUrl()) == url) {
result << c->clipId();
}
}
}
return result;
}
bool ProjectItemModel::loadFolders(Mlt::Properties &folders)
{
// At this point, we expect the folders properties to have a name of the form "x.y" where x is the id of the parent folder and y the id of the child.
......
......@@ -30,6 +30,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <QDomElement>
#include <QIcon>
#include <QReadWriteLock>
#include <QFileInfo>
#include <QSize>
class AbstractProjectItem;
......@@ -66,6 +67,9 @@ public:
/** @brief Returns a clip from the hierarchy, given its id */
std::shared_ptr<ProjectClip> getClipByBinID(const QString &binId);
/** @brief Returns a list of clips using the given url */
QStringList getClipByUrl(const QFileInfo &url) const;
/** @brief Helper to check whether a clip with a given id exists */
bool hasClip(const QString &binId);
......
......@@ -19,7 +19,7 @@ the Free Software Foundation, either version 3 of the License, or
#include "library/librarywidget.h"
#include "mainwindow.h"
#include "mltconnection.h"
#include "mltcontroller/bincontroller.h"
#include "mltcontroller/clipcontroller.h"
#include "monitor/monitormanager.h"
#include "profiles/profilemodel.hpp"
#include "profiles/profilerepository.hpp"
......@@ -62,9 +62,6 @@ Core::~Core()
if (m_monitorManager) {
delete m_monitorManager;
}
if (m_binController) {
m_binController->destroyBin();
}
// delete m_binWidget;
if (m_projectManager) {
delete m_projectManager;
......@@ -163,17 +160,9 @@ void Core::initGUI(const QUrl &Url)
m_projectManager = new ProjectManager(this);
m_binWidget = new Bin(m_projectItemModel);
m_binController = std::make_shared<BinController>();
m_library = new LibraryWidget(m_projectManager);
connect(m_library, SIGNAL(addProjectClips(QList<QUrl>)), m_binWidget, SLOT(droppedUrls(QList<QUrl>)));
connect(this, &Core::updateLibraryPath, m_library, &LibraryWidget::slotUpdateLibraryPath);
connect(m_binWidget, &Bin::storeFolder, m_binController.get(), &BinController::slotStoreFolder);
// connect(m_binController.get(), &BinController::slotProducerReady, m_binWidget, &Bin::slotProducerReady, Qt::DirectConnection);
// connect(m_binController.get(), &BinController::prepareTimelineReplacement, m_binWidget, &Bin::prepareTimelineReplacement, Qt::DirectConnection);
// connect(m_binController.get(), &BinController::requestAudioThumb, m_binWidget, &Bin::slotCreateAudioThumb);
connect(m_binController.get(), &BinController::abortAudioThumbs, m_binWidget, &Bin::abortAudioThumbs);
connect(m_binController.get(), &BinController::setDocumentNotes, m_projectManager, &ProjectManager::setDocumentNotes);
m_monitorManager = new MonitorManager(this);
// Producer queue, creating MLT::Producers on request
/*
......@@ -230,11 +219,6 @@ Monitor *Core::getMonitor(int id)
return m_monitorManager->projectMonitor();
}
std::shared_ptr<BinController> Core::binController()
{
return m_binController;
}
Bin *Core::bin()
{
return m_binWidget;
......
......@@ -20,7 +20,6 @@ the Free Software Foundation, either version 3 of the License, or
#include <memory>
class Bin;
class BinController;
class DocUndoStack;
class EffectStackModel;
class JobManager;
......@@ -88,8 +87,6 @@ public:
KdenliveDoc *currentDoc();
/** @brief Returns a pointer to the monitor manager. */
MonitorManager *monitorManager();
/** @brief Returns a pointer to the project bin controller. */
std::shared_ptr<BinController> binController();
/** @brief Returns a pointer to the view of the project bin. */
Bin *bin();
/** @brief Select a clip in the Bin from its id. */
......@@ -185,7 +182,6 @@ private:
MainWindow *m_mainWindow;
ProjectManager *m_projectManager;
MonitorManager *m_monitorManager;
std::shared_ptr<BinController> m_binController;
std::shared_ptr<ProjectItemModel> m_projectItemModel;
std::shared_ptr<JobManager> m_jobManager;
Bin *m_binWidget;
......
......@@ -22,7 +22,6 @@
#include "core.h"
#include "definitions.h"
#include "mainwindow.h"
#include "mltcontroller/bincontroller.h"
#include "bin/binplaylist.hpp"
#include "effects/effectsrepository.hpp"
#include "transitions/transitionsrepository.hpp"
......
......@@ -24,6 +24,7 @@
#include "bin/clipcreator.hpp"
#include "bin/model/markerlistmodel.hpp"
#include "bin/projectclip.h"
#include "bin/projectitemmodel.h"
#include "core.h"
#include "effects/effectsrepository.hpp"
#include "dialogs/profilesdialog.h"
......@@ -33,7 +34,6 @@
#include "jobs/jobmanager.h"
#include "kdenlivesettings.h"
#include "mainwindow.h"
#include "mltcontroller/bincontroller.h"
#include "mltcontroller/clipcontroller.h"
#include "profiles/profilemodel.hpp"
#include "profiles/profilerepository.hpp"
......@@ -643,23 +643,25 @@ void KdenliveDoc::setProjectFolder(const QUrl &url)
void KdenliveDoc::moveProjectData(const QString & /*src*/, const QString &dest)
{
// Move proxies
QList<std::shared_ptr<ClipController>> list = pCore->binController()->getControllerList();
QList<QUrl> cacheUrls;
for (int i = 0; i < list.count(); ++i) {
const std::shared_ptr<ClipController> &clip = list.at(i);
if (clip->clipType() == ClipType::Text) {
auto binClips = pCore->projectItemModel()->getAllClipIds();
// First step: all clips referenced by the bin model exist and are inserted
for (const auto &binClip : binClips) {
auto projClip = pCore->projectItemModel()->getClipByBinID(binClip);
if (projClip->clipType() == ClipType::Text) {
// the image for title clip must be moved
QUrl oldUrl = QUrl::fromLocalFile(clip->clipUrl());
QUrl oldUrl = QUrl::fromLocalFile(projClip->clipUrl());
if (!oldUrl.isEmpty()) {
QUrl newUrl = QUrl::fromLocalFile(dest + QStringLiteral("/titles/") + oldUrl.fileName());
KIO::Job *job = KIO::copy(oldUrl, newUrl);
if (job->exec()) {
clip->setProducerProperty(QStringLiteral("resource"), newUrl.toLocalFile());
projClip->setProducerProperty(QStringLiteral("resource"), newUrl.toLocalFile());
}
}
continue;
}
QString proxy = clip->getProducerProperty(QStringLiteral("kdenlive:proxy"));
QString proxy = projClip->getProducerProperty(QStringLiteral("kdenlive:proxy"));
if (proxy.length() > 2 && QFile::exists(proxy)) {
QUrl pUrl = QUrl::fromLocalFile(proxy);
if (!cacheUrls.contains(pUrl)) {
......@@ -1180,7 +1182,7 @@ void KdenliveDoc::slotProxyCurrentItem(bool doProxy, QList<std::shared_ptr<Proje
t == ClipType::SlideShow) &&
item->isReady()) {
if ((doProxy && !force && item->hasProxy()) ||
(!doProxy && !item->hasProxy() && pCore->binController()->hasClip(item->AbstractProjectItem::clipId()))) {
(!doProxy && !item->hasProxy() && pCore->projectItemModel()->hasClip(item->AbstractProjectItem::clipId()))) {
continue;
}
......@@ -1199,7 +1201,7 @@ void KdenliveDoc::slotProxyCurrentItem(bool doProxy, QList<std::shared_ptr<Proje
// Revert to picture aspect ratio
newProps.insert(QStringLiteral("aspect_ratio"), QStringLiteral("1"));
}
if (!pCore->binController()->hasClip(item->AbstractProjectItem::clipId())) {
if (!pCore->projectItemModel()->hasClip(item->AbstractProjectItem::clipId())) {
// Force clip reload
newProps.insert(QStringLiteral("resource"), item->url());
}
......@@ -1302,7 +1304,6 @@ void KdenliveDoc::loadDocumentProperties()
void KdenliveDoc::updateProjectProfile(bool reloadProducers)
{
pCore->bin()->abortAudioThumbs();
pCore->jobManager()->slotCancelJobs();
double fps = pCore->getCurrentFps();
double fpsChanged = m_timecode.fps() / fps;
......
......@@ -208,7 +208,6 @@ CollapsibleEffectView::CollapsibleEffectView(std::shared_ptr<EffectItemModel> ef
CollapsibleEffectView::~CollapsibleEffectView()
{
qDebug() << "deleting collapsibleeffectview";
delete m_menu;
}
void CollapsibleEffectView::setWidgetHeight(qreal value)
......
......@@ -29,7 +29,6 @@
#include "kdenlivesettings.h"
#include "klocalizedstring.h"
#include "macros.hpp"
#include "mltcontroller/clip.h"
#include "profiles/profilemodel.hpp"
#include "project/dialogs/slideshowclip.h"
#include "xml/xml.hpp"
......@@ -420,7 +419,7 @@ void LoadJob::processMultiStream()
// This helper lambda request addition of a given stream
auto addStream = [ this, parentId = std::move(parent) ](int vindex, int aindex, Fun &undo, Fun &redo)
{
auto clone = Clip::clone(m_producer);
auto clone = ProjectClip::cloneProducer(m_producer);
clone->set("video_index", vindex);
clone->set("audio_index", aindex);
QString id;
......
......@@ -43,7 +43,6 @@
#include "library/librarywidget.h"
#include "mainwindowadaptor.h"
#include "mltconnection.h"
#include "mltcontroller/bincontroller.h"
#include "mltcontroller/clipcontroller.h"
#include "monitor/monitor.h"
#include "monitor/monitormanager.h"
......@@ -824,8 +823,8 @@ void MainWindow::slotConnectMonitors()
// SLOT(slotDeleteProjectClips(QStringList,QMap<QString,QString>)));
connect(m_clipMonitor, &Monitor::refreshClipThumbnail, pCore->bin(), &Bin::slotRefreshClipThumbnail);
connect(m_projectMonitor, &Monitor::requestFrameForAnalysis, this, &MainWindow::slotMonitorRequestRenderFrame);
connect(m_projectMonitor, &Monitor::createSplitOverlay, this, &MainWindow::createSplitOverlay);
connect(m_projectMonitor, &Monitor::removeSplitOverlay, this, &MainWindow::removeSplitOverlay);
connect(m_projectMonitor, &Monitor::createSplitOverlay, this, &MainWindow::createSplitOverlay, Qt::DirectConnection);
connect(m_projectMonitor, &Monitor::removeSplitOverlay, this, &MainWindow::removeSplitOverlay, Qt::DirectConnection);
}
void MainWindow::createSplitOverlay(Mlt::Filter *filter)
......@@ -1794,7 +1793,7 @@ void MainWindow::setRenderingFinished(const QString &url, int status, const QStr
void MainWindow::addProjectClip(const QString &url)
{
if (pCore->currentDoc()) {
QStringList ids = pCore->binController()->getBinIdsByResource(QFileInfo(url));
QStringList ids = pCore->projectItemModel()->getClipByUrl(QFileInfo(url));
if (!ids.isEmpty()) {
// Clip is already in project bin, abort
return;
......@@ -1807,7 +1806,7 @@ void MainWindow::addProjectClip(const QString &url)
void MainWindow::addTimelineClip(const QString &url)
{
if (pCore->currentDoc()) {
QStringList ids = pCore->binController()->getBinIdsByResource(QFileInfo(url));
QStringList ids = pCore->projectItemModel()->getClipByUrl(QFileInfo(url));
if (!ids.isEmpty()) {
pCore->selectBinClip(ids.constFirst());
slotInsertClipInsert();
......
set(kdenlive_SRCS
${kdenlive_SRCS}
mltcontroller/bincontroller.cpp
mltcontroller/clip.cpp
# mltcontroller/bincontroller.cpp
# mltcontroller/clip.cpp
mltcontroller/clipcontroller.cpp
mltcontroller/clippropertiescontroller.cpp
# mltcontroller/effectscontroller.cpp
......
/***************************************************************************
* Copyright (C) 2014 by Jean-Baptiste Mardelle (jb@kdenlive.org) *
* *
* 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 "bincontroller.h"
#include "bin/model/markerlistmodel.hpp"
#include "bin/projectitemmodel.h"
#include "clip.h"
#include "clipcontroller.h"
#include "core.h"
#include "kdenlivesettings.h"
BinController::BinController(const QString &profileName)
: QObject()
{
Q_UNUSED(profileName)
// resetProfile(profileName.isEmpty() ? KdenliveSettings::current_profile() : profileName);
}
BinController::~BinController()
{
qDebug() << "/// delete bincontroller";
qDebug() << "REMAINING CLIPS: " << m_clipList.keys();
destroyBin();
}
void BinController::destroyBin()
{
if (m_binPlaylist) {
// m_binPlaylist.release();
m_binPlaylist->clear();
}
qDeleteAll(m_extraClipList);
m_extraClipList.clear();
m_clipList.clear();
}
void BinController::loadExtraProducer(const QString &id, Mlt::Producer *prod)
{
if (m_extraClipList.contains(id)) {
return;
}
m_extraClipList.insert(id, prod);
}
QStringList BinController::getProjectHashes()
{
QStringList hashes;
QMapIterator<QString, std::shared_ptr<ClipController>> i(m_clipList);
hashes.reserve(m_clipList.count());
while (i.hasNext()) {
i.next();
hashes << i.value()->getClipHash();
}
hashes.removeDuplicates();
return hashes;
}
void BinController::slotStoreFolder(const QString &folderId, const QString &parentId, const QString &oldParentId, const QString &folderName)
{
if (!oldParentId.isEmpty()) {
// Folder was moved, remove old reference
QString oldPropertyName = "kdenlive:folder." + oldParentId + QLatin1Char('.') + folderId;
m_binPlaylist->set(oldPropertyName.toUtf8().constData(), (char *)nullptr);
}
QString propertyName = "kdenlive:folder." + parentId + QLatin1Char('.') + folderId;
if (folderName.isEmpty()) {
// Remove this folder info
m_binPlaylist->set(propertyName.toUtf8().constData(), (char *)nullptr);
} else {
m_binPlaylist->set(propertyName.toUtf8().constData(), folderName.toUtf8().constData());
}
}
int BinController::clipCount() const
{
return m_clipList.size();
}
void BinController::replaceBinPlaylistClip(const QString &id, const std::shared_ptr<Mlt::Producer> &producer)
{
removeBinPlaylistClip(id);
m_binPlaylist->append(*producer.get());
}
void BinController::removeBinPlaylistClip(const QString &id)
{
int size = m_binPlaylist->count();
for (int i = 0; i < size; i++) {
QScopedPointer<Mlt::Producer> prod(m_binPlaylist->get_clip(i));
QString prodId = prod->parent().get("kdenlive:id");
if (prodId == id) {
m_binPlaylist->remove(i);
break;
}
}
}
bool BinController::hasClip(const QString &id)
{
return m_clipList.contains(id);
}
std::shared_ptr<Mlt::Producer> BinController::getBinProducer(const QString &id)
{
// TODO: framebuffer speed clips
if (!m_clipList.contains(id)) {
qDebug() << "ERROR: requesting invalid bin producer: " << id;
return nullptr;
}
return m_clipList[id]->originalProducer();
}
void BinController::duplicateFilters(std::shared_ptr<Mlt::Producer> original, Mlt::Producer clone)
{
Mlt::Service clipService(original->get_service());
Mlt::Service dupService(clone.get_service());
for (int ix = 0; ix < clipService.filter_count(); ++ix) {
QScopedPointer<Mlt::Filter> filter(clipService.filter(ix));
// Only duplicate Kdenlive filters
if (filter->is_valid()) {
QString effectId = filter->get("kdenlive_id");
if (effectId.isEmpty()) {
continue;
}
// looks like there is no easy way to duplicate a filter,
// so we will create a new one and duplicate its properties
auto *dup = new Mlt::Filter(*original->profile(), filter->get("mlt_service"));
if ((dup != nullptr) && dup->is_valid()) {
for (int i = 0; i < filter->count(); ++i) {
QString paramName = filter->get_name(i);
if (paramName.at(0) != QLatin1Char('_')) {
dup->set(filter->get_name(i), filter->get(i));
}
}
dupService.attach(*dup);
}
delete dup;
}
}
}
QString BinController::xmlFromId(const QString &id)
{
if (!m_clipList.contains(id)) {
qDebug() << "Error: impossible to retrieve xml from unknown bin clip";
return QString();
}
std::shared_ptr<ClipController> controller = m_clipList[id];
std::shared_ptr<Mlt::Producer> original = controller->originalProducer();
QString xml = getProducerXML(original);
QDomDocument mltData;
mltData.setContent(xml);
QDomElement producer = mltData.documentElement().firstChildElement(QStringLiteral("producer"));
QString str;
QTextStream stream(&str);
producer.save(stream, 4);
return str;
}