Reimplement change speed job for bin clip (currently freezes because of mutex...

Reimplement change speed job for bin clip (currently freezes because of mutex issue with job management)
parent 7f5b5512
......@@ -6,6 +6,7 @@ set(kdenlive_SRCS
jobs/loadjob.cpp
jobs/meltjob.cpp
jobs/scenesplitjob.cpp
jobs/speedjob.cpp
jobs/stabilizejob.cpp
jobs/thumbjob.cpp
# jobs/cutclipjob.cpp
......
......@@ -50,7 +50,8 @@ public:
THUMBJOB = 6,
ANALYSECLIPJOB = 7,
LOADJOB = 8,
AUDIOTHUMBJOB = 9
AUDIOTHUMBJOB = 9,
SPEEDJOB = 10
};
AbstractClipJob(JOBTYPE type, const QString &id, QObject *parent = nullptr);
virtual ~AbstractClipJob();
......
......@@ -124,6 +124,7 @@ std::shared_ptr<Mlt::Producer> LoadJob::loadPlaylist(QString &resource)
xmlProfile->set_explicit(0);
std::unique_ptr<Mlt::Producer> producer(new Mlt::Producer(*xmlProfile, "xml", resource.toUtf8().constData()));
if (!producer->is_valid()) {
qDebug()<<"////// ERROR, CANNOT LOAD SELECTED PLAYLIST: "<<resource;
return nullptr;
}
if (pCore->getCurrentProfile()->isCompatible(xmlProfile.get())) {
......@@ -132,6 +133,7 @@ std::shared_ptr<Mlt::Producer> LoadJob::loadPlaylist(QString &resource)
resource.prepend(QStringLiteral("xml:"));
} else {
// This is currently crashing so I guess we'd better reject it for now
qDebug()<<"////// ERROR, INCOMPATIBLE PROFILE: "<<resource;
return nullptr;
// path.prepend(QStringLiteral("consumer:"));
}
......
......@@ -44,6 +44,7 @@ MeltJob::MeltJob(const QString &binId, JOBTYPE type, bool useProducerProfile, in
, m_useProducerProfile(useProducerProfile)
, m_in(in)
, m_out(out)
, m_requiresFilter(true)
{
}
......@@ -229,7 +230,8 @@ bool MeltJob::startJob()
}
}
*/
if ((m_filter == nullptr) || !m_filter->is_valid()) {
if (m_requiresFilter && (m_filter == nullptr || !m_filter->is_valid())) {
m_errorMessage.append(i18n("Cannot create filter."));
m_successful = false;
m_done = true;
......@@ -277,3 +279,4 @@ void MeltJob::mltFrameCallback(int pos)
emit jobProgress((int)(100 * pos / m_length));
}
}
......@@ -85,6 +85,8 @@ protected:
bool m_useProducerProfile;
int m_in, m_out;
int m_length;
// @brief Does this job require a filter
bool m_requiresFilter;
};
#endif
/***************************************************************************
* Copyright (C) 2018 by Jean-Baptiste Mardelle (jb@kdenlive.org) *
* Copyright (C) 2017 by Nicolas Carion *
* *
* This file is part of Kdenlive. See www.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) version 3 or any later version accepted by the *
* membership of KDE e.V. (or its successor approved by the membership *
* of KDE e.V.), which shall act as a proxy defined in Section 14 of *
* version 3 of the license. *
* *
* 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, see <http://www.gnu.org/licenses/>. *
***************************************************************************/
#include "speedjob.hpp"
#include "bin/clipcreator.hpp"
#include "bin/projectclip.h"
#include "bin/projectfolder.h"
#include "bin/projectitemmodel.h"
#include "core.h"
#include "jobmanager.h"
#include "kdenlivesettings.h"
#include "project/clipstabilize.h"
#include "ui_scenecutdialog_ui.h"
#include <QScopedPointer>
#include <klocalizedstring.h>
#include <QInputDialog>
#include <mlt++/Mlt.h>
SpeedJob::SpeedJob(const QString &binId, double speed, const QString &destUrl)
: MeltJob(binId, SPEEDJOB, false, -1, -1)
, m_speed(speed)
, m_destUrl(destUrl)
{
m_requiresFilter = false;
}
const QString SpeedJob::getDescription() const
{
return i18n("Change clip speed");
}
void SpeedJob::configureConsumer()
{
m_consumer.reset(new Mlt::Consumer(m_profile, "xml", m_destUrl.toUtf8().constData()));
m_consumer->set("terminate_on_pause", 1);
m_consumer->set("title", "Speed Change");
m_consumer->set("real_time", -KdenliveSettings::mltthreads());
}
void SpeedJob::configureProducer()
{
if (!qFuzzyCompare(m_speed, 1.0)) {
QString resource = m_producer->get("resource");
m_producer.reset(new Mlt::Producer(m_profile, "timewarp", QStringLiteral("%1:%2").arg(m_speed).arg(resource).toUtf8().constData()));
}
}
void SpeedJob::configureFilter()
{
}
// static
int SpeedJob::prepareJob(std::shared_ptr<JobManager> ptr, const std::vector<QString> &binIds, int parentId, QString undoString)
{
// Show config dialog
bool ok;
int speed = QInputDialog::getInt(QApplication::activeWindow(), i18n("Clip Speed"), i18n("Percentage"), 100, -100000, 100000, 1, &ok);
if (!ok) {
return -1;
}
std::unordered_map<QString, QString> destinations; // keys are binIds, values are path to target files
for (const auto &binId : binIds) {
auto binClip = pCore->projectItemModel()->getClipByBinID(binId);
// Filter several clips, destination points to a folder
QString mltfile = QFileInfo(binClip->url()).absoluteFilePath() + QStringLiteral(".mlt");
destinations[binId] = mltfile;
}
// Now we have to create the jobs objects. This is trickier than usual, since the parameters are differents for each job (each clip has its own destination). We have to construct a lambda that does that.
auto createFn = [ dest = std::move(destinations), fSpeed = speed/100.0 ](const QString &id)
{
return std::make_shared<SpeedJob>(id, fSpeed, dest.at(id));
};
// We are now all set to create the job. Note that we pass all the parameters directly through the lambda, hence there are no extra parameters to the function
using local_createFn_t = std::function<std::shared_ptr<SpeedJob>(const QString &)>;
return ptr->startJob<SpeedJob>(binIds, parentId, std::move(undoString), local_createFn_t(std::move(createFn)));
}
bool SpeedJob::commitResult(Fun &undo, Fun &redo)
{
Q_ASSERT(!m_resultConsumed);
if (!m_done) {
qDebug() << "ERROR: Trying to consume invalid results";
return false;
}
m_resultConsumed = true;
if (!m_successful) {
return false;
}
auto binClip = pCore->projectItemModel()->getClipByBinID(m_clipId);
// We store the stabilized clips in a sub folder with this name
const QString folderName(i18n("Speed Change"));
QString folderId = QStringLiteral("-1");
bool found = false;
// We first try to see if it exists
auto containingFolder = std::static_pointer_cast<ProjectFolder>(binClip->parent());
for (int i = 0; i < containingFolder->childCount(); ++i) {
auto currentItem = std::static_pointer_cast<AbstractProjectItem>(containingFolder->child(i));
if (currentItem->itemType() == AbstractProjectItem::FolderItem && currentItem->name() == folderName) {
found = true;
folderId = currentItem->clipId();
break;
}
}
if (!found) {
// if it was not found, we create it
pCore->projectItemModel()->requestAddFolder(folderId, folderName, binClip->parent()->clipId(), undo, redo);
}
auto id = ClipCreator::createClipFromFile(m_destUrl, folderId, pCore->projectItemModel(), undo, redo);
return id != QStringLiteral("-1");
}
/***************************************************************************
* Copyright (C) 2018 by Jean-Baptiste Mardelle (jb@kdenlive.org) *
* Copyright (C) 2017 by Nicolas Carion *
* *
* This file is part of Kdenlive. See www.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) version 3 or any later version accepted by the *
* membership of KDE e.V. (or its successor approved by the membership *
* of KDE e.V.), which shall act as a proxy defined in Section 14 of *
* version 3 of the license. *
* *
* 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, see <http://www.gnu.org/licenses/>. *
***************************************************************************/
#pragma once
#include "meltjob.h"
#include <unordered_map>
#include <unordered_set>
/**
* @class SpeedJob
* @brief Create a timewarp producer to change speed of a producer
*
*/
class JobManager;
class SpeedJob : public MeltJob
{
Q_OBJECT
public:
/** @brief Creates a timewarp producer
@param speed The speed value
*/
SpeedJob(const QString &binId, double speed, const QString &destUrl);
// This is a special function that prepares the stabilize job for a given list of clips.
// Namely, it displays the required UI to configure the job and call startJob with the right set of parameters
// Then the job is automatically put in queue. Its id is returned
static int prepareJob(std::shared_ptr<JobManager> ptr, const std::vector<QString> &binIds, int parentId, QString undoString);
bool commitResult(Fun &undo, Fun &redo) override;
const QString getDescription() const override;
protected:
// @brief create and configure consumer
void configureConsumer() override;
// @brief create and configure producer
void configureProducer() override;
// @brief create and configure filter
void configureFilter() override;
double m_speed;
QString m_destUrl;
};
......@@ -39,6 +39,7 @@
#include "hidetitlebars.h"
#include "jobs/jobmanager.h"
#include "jobs/scenesplitjob.hpp"
#include "jobs/speedjob.hpp"
#include "jobs/stabilizejob.hpp"
#include "kdenlivesettings.h"
#include "layoutmanagement.h"
......@@ -3211,20 +3212,16 @@ void MainWindow::buildDynamicActions()
QAction *action = new QAction(i18n("Automatic scene split"), m_extraFactory->actionCollection());
ts->addAction(action->text(), action);
connect(action, &QAction::triggered,
[&]() { pCore->jobManager()->startJob<SceneSplitJob>(pCore->bin()->selectedClipsIds(), {}, i18n("Stabilize clips")); });
[&]() { pCore->jobManager()->startJob<SceneSplitJob>(pCore->bin()->selectedClipsIds(), {}, i18np("Stabilize clip", "Stabilize clips", pCore->bin()->selectedClipsIds().size())); });
}
}
// TODO refac see if we want to reimplement speed change job. If so, maybe use better algorithm?
/*
if (KdenliveSettings::producerslist().contains(QStringLiteral("timewarp"))) {
if (true /* TODO: check if timewarp producer is available */) {
QAction *action = new QAction(i18n("Duplicate clip with speed change"), m_extraFactory->actionCollection());
QStringList stabJob;
stabJob << QString::number((int)AbstractClipJob::FILTERCLIPJOB) << QStringLiteral("timewarp");
action->setData(stabJob);
ts->addAction(action->text(), action);
connect(action, &QAction::triggered, pCore->bin(), &Bin::slotStartClipJob);
connect(action, &QAction::triggered,
[&]() {
pCore->jobManager()->startJob<SpeedJob>(pCore->bin()->selectedClipsIds(), {}, i18n("Change clip speed")); });
}
*/
// TODO refac reimplement analyseclipjob
/*
QAction *action = new QAction(i18n("Analyse keyframes"), m_extraFactory->actionCollection());
......
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